Within-host diversity and minor variant analyses in samples from Houston Methodist Hospital, 2021

Sample characteristics and inclusion criteria

source("./scripts/startup.R")
The following packages have been unloaded:
broom, tableone, arrow, magrittr, scales, lubridate, ggExtra, ggsci, pheatmap, Biostrings, GenomeInfoDb, XVector, IRanges, S4Vectors, BiocGenerics, ggrepel, data.table, ggpubr, viridis, viridisLite, gggenes, ggforce, glmnet, Matrix, cowplot, forcats, stringr, dplyr, purrr, readr, tidyr, tibble, ggplot2, tidyverse, pacman

Loading required package: pacman
##### Load libraries and define recurring functions / variables
#all mcov samples we have ever received - reformat sample names to be consistent
mcov_samples_all <- fread("full_lineage_report_20220507.tsv", data.table=F) %>% 
  mutate(MCoVNumber=mcov_reformat(taxon)) %>% 
  filter(startsWith(MCoVNumber, "MCoV")) %>% 
  filter(MCoVNumber!="MCoV30904") #remove one sample with inconsistently formatted duplicates

#run and date info; keep only earliest sample from the same patient
mcov_info <- fread("sample_date_and_run.csv", data.table=F) %>% 
  mutate(COLLECTION_DT=as.Date(COLLECTION_DT, "%m/%d/%y"),
         MCoVNumber=str_remove(mcov_id, "-")) %>%
  arrange(COLLECTION_DT) %>% filter(!duplicated(PatientID))

#samples we received that we're interested in (December 2020-November 2021)
mcov_samples_1 <- mcov_samples_all %>% filter(!taxon %in% dup65.66) %>% 
  filter(MCoVNumber %in% mcov_info$MCoVNumber) %>% left_join(mcov_info)
Joining, by = "MCoVNumber"
#all samples sequenced in each run (including those from outside of this study period) -- sometimes relevant for run QC purposes
runs_all_samples <- fread("run_samples.csv", data.table = F) %>% 
  mutate(MCoVNumber=str_remove(`Sample ID`,"-"), run=Run) %>% 
  select(run, MCoVNumber)

#summary stats on coverage of each sample; drop the run 65 duplicates and join coverage info to main dataset
d1 = fread('coverage_levels_20220507.csv', data.table = F) %>% 
  filter(duplicated(samplename)) %>% pull(samplename)
d2 = fread('coverage_levels_20220507.csv', data.table = F) %>% 
  filter(samplename %in% d1) %>% filter(!duplicated(samplename)) %>% 
  pull(filename)
coverage_levels <- fread('coverage_levels_20220507.csv', data.table = F) %>% 
  filter(!filename %in% d2) %>% filter(samplename!="MCoV30904") %>% select(-1)
# join dataframes
mcov_samples<-mcov_samples_1 %>% 
  select(MCoVNumber, lineage, scorpio_call, qc_status, 
         COLLECTION_DT, INSTRUMENT, INSTRUMENT_RESULT, run=run_group) %>% 
  left_join(coverage_levels, by=c("MCoVNumber"="samplename"))

mcov_samples_with_ct<-mcov_samples %>% filter(INSTRUMENT_RESULT<50) %>% 
  mutate(CT=INSTRUMENT_RESULT)
#what's the relationship between CT value and read coverage?
coverage_all<-mcov_samples_with_ct %>% ggplot(aes(x=CT, y=median_coverage)) + 
  geom_point(alpha=0.07) + theme_bw() + xlab("Ct value") + ylab("Sample median depth")
#how does coverage in high-CT samples compare with the rest of them?
coverage_ct_cat<-mcov_samples_with_ct %>% mutate(sample_ct=if_else(CT>=40, "CT>=40", "CT<40")) %>% 
  ggplot(aes(x=sample_ct, y=median_coverage)) + 
  geom_point(alpha=0.2, position=position_jitter(width=0.25)) + 
  geom_boxplot(color="red", alpha=0) + theme_bw() + 
  xlab("Ct value") + ylab("Sample median depth")

Run-level QC

#are there any runs where high-CT samples have unusually high coverage? treat CT>40 samples as negative controls and eliminate runs where their coverage is not different from those of the rest of the samples
test_group<-mcov_samples_with_ct %>% mutate(is_neg=if_else(CT>=40,1,0)) %>% 
  group_by(run) %>% mutate(n_negs=sum(is_neg)) %>% filter(n_negs>=3) %>% 
  ungroup() %>% mutate(sampletype=if_else(is_neg==1, "negctrl","sample"))
runs_to_drop1 = test_group %>% group_by(run) %>% 
  summarise(t_test_p=t.test(fraction_1000x_coverage~sampletype)$p.value) %>% 
  arrange(desc(t_test_p)) %>% filter(t_test_p>0.01) %>% pull(run)
runs_to_drop2 = test_group %>% group_by(run) %>% 
  summarise(t_test_p=t.test(median_coverage~sampletype)$p.value) %>% 
  arrange(desc(t_test_p)) %>% filter(t_test_p>0.01) %>% pull(run)

############ 
runs_to_drop<-union(runs_to_drop1, runs_to_drop2)
saveRDS(runs_to_drop, "processing/runs_to_drop.rds")

mcov_samples_with_ct %>% pull(run) %>% unique()
 [1] "Run_11" "Run_12" "Run_15" "Run_13" "Run_16" "Run_18" "Run_19" "Run_20" "Run_21" "Run_22" "Run_23"
[12] "Run_24" "Run_25" "Run_26" "Run_27" "Run_28" "Run_29" "Run_30" "Run_31" "Run_35" "Run_32" "Run_33"
[23] "Run_34" "Run_37" "Run_36" "Run_39" "Run_40" "Run_41" "Run_43" "Run_44" "Run_46" "Run_48" "Run_49"
[34] "Run_51" "Run_52" "Run_53" "Run_57" "Run_58" "Run_59" "Run_61" "Run_62" "Run_63" "Run_64" "Run_65"
[45] "Run_66" "Run_68" "Run_69" "Run_70" "Run_71" "Run_72" "Run_73" "Run_74" "Run_75" "Run_76" "Run_77"
[56] "Run_78" "Run_79" "Run_80" "Run_81" "Run_82" "Run_83" "Run_85" "Run_86" "Run_87" "Run_88" "Run_89"
[67] "Run_90" "Run_14" "Run_17"
test_group %>% group_by(run, sampletype) %>% summarize(counts = n()) %>% 
  filter(run %in% runs_to_drop) %>% nrow()
`summarise()` has grouped output by 'run'. You can override using the `.groups` argument.
[1] 44
mcov_samples_with_ct %>% pull(run) %>% unique()
 [1] "Run_11" "Run_12" "Run_15" "Run_13" "Run_16" "Run_18" "Run_19" "Run_20" "Run_21" "Run_22" "Run_23"
[12] "Run_24" "Run_25" "Run_26" "Run_27" "Run_28" "Run_29" "Run_30" "Run_31" "Run_35" "Run_32" "Run_33"
[23] "Run_34" "Run_37" "Run_36" "Run_39" "Run_40" "Run_41" "Run_43" "Run_44" "Run_46" "Run_48" "Run_49"
[34] "Run_51" "Run_52" "Run_53" "Run_57" "Run_58" "Run_59" "Run_61" "Run_62" "Run_63" "Run_64" "Run_65"
[45] "Run_66" "Run_68" "Run_69" "Run_70" "Run_71" "Run_72" "Run_73" "Run_74" "Run_75" "Run_76" "Run_77"
[56] "Run_78" "Run_79" "Run_80" "Run_81" "Run_82" "Run_83" "Run_85" "Run_86" "Run_87" "Run_88" "Run_89"
[67] "Run_90" "Run_14" "Run_17"
test_group %>% group_by(run, sampletype) %>% summarize(counts = n()) %>% 
  filter(sampletype=="negctrl") %>% arrange(counts) %>% mutate(dropped = run %in% runs_to_drop) %>%
  ggplot(aes(dropped,counts, label=run)) + geom_boxplot() + geom_point() + geom_text_repel() + theme_pubr()
`summarise()` has grouped output by 'run'. You can override using the `.groups` argument.

runs_kept = mcov_samples_with_ct$run[!mcov_samples_with_ct$run %in% runs_to_drop] %>% unique()
f1 = mcov_samples_with_ct %>% mutate(run_kept = run %in% runs_kept) %>% 
  ggplot(aes(INSTRUMENT_RESULT, fraction_1000x_coverage, 
                                         color = run_kept)) + 
  geom_point(shape=".", alpha = 0.5) + theme_pubr() + 
  theme(plot.title = element_text(size = 40, face = "bold")) + 
  geom_vline(xintercept=40, color = "red") + geom_smooth()
f1


f2 = mcov_samples_with_ct %>% mutate(run_kept = run %in% runs_kept) %>% 
  ggplot(aes(INSTRUMENT_RESULT, log10(median_coverage), color = run_kept)) + 
  geom_point(shape=".", alpha = 0.5) + theme_pubr() + 
  theme(plot.title = element_text(size = 40, face = "bold")) + 
  geom_vline(xintercept=40, color = "red") + geom_smooth()

runs_samples_dots = ggarrange(f1, f2, ncol = 1, nrow = 2, align = "v", common.legend = T)
`geom_smooth()` using method = 'gam' and formula = 'y ~ s(x, bs = "cs")'`geom_smooth()` using method = 'gam' and formula = 'y ~ s(x, bs = "cs")'`geom_smooth()` using method = 'gam' and formula = 'y ~ s(x, bs = "cs")'
runs_samples_dots
ggsave("ggsave/runs_samples_dots.pdf", plot = runs_samples_dots, width = 3, height = 4.5)

mcov_samples_with_ct %>% colnames()
 [1] "MCoVNumber"              "lineage"                 "scorpio_call"           
 [4] "qc_status"               "COLLECTION_DT"           "INSTRUMENT"             
 [7] "INSTRUMENT_RESULT"       "run"                     "fraction_100x_coverage" 
[10] "fraction_200x_coverage"  "fraction_500x_coverage"  "fraction_1000x_coverage"
[13] "median_coverage"         "CT"                     
### plot boxplot of the runs
stmp = mcov_samples_with_ct %>% mutate(run_dropped = run %in%   
    runs_to_drop) %>% mutate(run = as.numeric(gsub("Run_", "", run))) %>% 
    mutate(is_neg=if_else(CT>=40,1,0))

label_at <- function(n) function(x) ifelse(x %% n == 0, x, "")


f3 = ggplot(stmp, aes(x=run, y=fraction_1000x_coverage, group = run, 
             color = run_dropped, fill = run_dropped)) + 
  geom_boxplot() + 
  geom_point(data = stmp %>% filter(is_neg == T), 
             aes(run, fraction_1000x_coverage), color = "red", alpha = .9, 
             shape = 1) + 
  scale_fill_grey(start = 1, end = 0.8) + 
  scale_x_continuous(breaks = seq(10,90,2), limits = c(10,92), labels = label_at(10)) +  
  scale_color_grey(start=0, end=0.6) +
  theme(axis.text.x = element_text(angle = 90, vjust = .5)) +
  labs( x = NULL)
  
f4 = ggplot(stmp, aes(x=run, y=log10(median_coverage), group = run, 
             color = run_dropped, fill = run_dropped)) + 
  geom_boxplot() + 
  geom_point(data = stmp %>% filter(is_neg == T), 
             aes(run, log10(median_coverage)), color = "red", alpha = .9, 
             shape = 1) + 
  scale_fill_grey(start = 1, end = 0.8) + 
  scale_x_continuous(breaks = seq(10,90,2), limits = c(10,92), labels = label_at(10)) +  
  scale_color_grey(start=0, end=0.6) +
  theme(axis.text.x = element_text(angle = 90, vjust = .5)) +
  labs( x = NULL)

run_filter_red = ggarrange(f3, f4, ncol = 1, nrow = 2, align = "v", common.legend = T)
((
  run_filter_red_plot = annotate_figure(run_filter_red,
               top = text_grob("red circles: samples Ct>40", color = "red", size = 10))
))


ggsave("ggsave/run_filter_red_plot.pdf", plot = run_filter_red_plot, width = 6, height = 4)

Sample-level QC

#nextclade QC
nc<-fread("houston_nextclade.tsv", sep='\t', data.table = F) %>% 
  mutate(MCoVNumber=regmatches(seqName, regexpr("[M,R,S,O]CoV.[0-9]+", seqName)) %>% 
           str_remove("-") %>% str_remove("_")) %>% filter(!duplicated(MCoVNumber))
nextclade_bad_samples<-nc %>% filter(qc.overallStatus %in% c("bad")) %>% pull(MCoVNumber)
#drop bad runs and samples that don't pass pangolin QC or nextclade QC
mcov_samples_filtered<-mcov_samples %>% filter(!run %in% runs_to_drop) %>% 
  filter(qc_status=="pass") %>% filter(!MCoVNumber %in% nextclade_bad_samples) %>% 
  filter(scorpio_call!="Omicron (BA.1-like)") %>% 
 ##### #main coverage criterion for fair comparisons: X depth over Y percent of the genome
  filter(fraction_100x_coverage>=0.98) %>% droplevels()

#what's the distribution of CT values?
ct_distribution_after_qc<-mcov_samples_filtered %>% filter(INSTRUMENT_RESULT<50) %>% 
  ggplot(aes(x=INSTRUMENT_RESULT)) + geom_histogram(binwidth=1) + theme_bw() + 
  xlab("Ct value") + labs(caption="After exclusion criteria")
#How did exclusion criteria change distribution of sample Ct values?

ct_distribution_after_qc<-mcov_samples_filtered %>% filter(INSTRUMENT_RESULT<50) %>% ggplot(aes(x=INSTRUMENT_RESULT)) + geom_histogram(binwidth=1) + theme_bw() + xlab("Ct value")

ct_distribution_before_qc<-mcov_samples %>% filter(INSTRUMENT_RESULT<50) %>% ggplot(aes(x=INSTRUMENT_RESULT)) + geom_histogram(binwidth=1) + theme_bw() + xlab("Ct value") + labs(caption="Before exclusion criteria")
#ct_inclusion<-plot_grid(ct_distribution_before_qc, ct_distribution_after_qc, nrow=2)

#ct_inclusion


ct_distribution_after_qc<-mcov_samples_filtered %>% filter(INSTRUMENT_RESULT<50)
ct_distribution_before_qc<-mcov_samples %>% filter(INSTRUMENT_RESULT<50)
plot1_ct_before_after = ggplot(aes(x=INSTRUMENT_RESULT), data = ct_distribution_before_qc) + 
  geom_histogram(binwidth = 1, fill = "grey") +
  geom_histogram(data = ct_distribution_after_qc, binwidth=1) + theme_pubr() + 
  xlab("Ct value") + ylab("# samples") #+ geom_vline(xintercept = 26,
                                               #     linetype = "dashed")

ggsave("ggsave/plot1_ct_before_after.pdf", plot1_ct_before_after, height = 2, width = 4)

Preliminary minor variant distributions

#nucleotide positions of all primers used in dataset; will exclude 
primers = fread("nCoV-2019.artic_v3.primer.txt", sep="\t", header=FALSE, data.table=F) %>% 
  select(start = V2, end = V3)
primer_positions_v3<-as.numeric()
for (i in 1:nrow(primers)){
  primer_positions_v3<-c(primer_positions_v3, primers[i,]$start:primers[i,]$end)
}

primers = fread("nCoV-2019.artic_v4.primer.bed", sep="\t", 
                header=FALSE, data.table = F) %>% select(start = V2, end = V3)
primer_positions_v4<-as.numeric()
for (i in 1:nrow(primers)){
  primer_positions_v4<-c(primer_positions_v4, primers[i,]$start:primers[i,]$end)
}

primers = fread("V4.1.bed", sep="\t", header=FALSE, data.table=F) %>% 
  select(start = V2, end = V3)
primer_positions_v4.1 <- as.numeric()
for (i in 1:nrow(primers)){
  primer_positions_v4.1 <- c(primer_positions_v4.1, primers[i,]$start:primers[i,]$end)
}

problem_sites = fread("problematic_sites_sarsCov2_v8-20211027.vcf", skip = 88)

primer_positions_all <- c(primer_positions_v3, primer_positions_v4, primer_positions_v4.1,
                          problem_sites$POS) %>% unique()

saveRDS(primer_positions_all, "primer_positions_all.rds")

#reference genome with nucleotide positions of genes
genes <- fread("ntpos_gene_update.csv", data.table = F)
gene_names <- genes %>% pull(gene_id) %>% unique()
genes$gene_id <- factor(genes$gene_id, levels = gene_names)
### Update this if you change sample inclusion criteria
### Update this if change the thresholds for counting minor variants
#file was already filtered to sites with minimum 100 reads depth and A,C,T,G minor variant present and binomial significance check passed. Further filtering:


# depth_at_site<-100
# minor_frequency<-0.01
# total_minor_reads<-50
# #
# minor_variant_sites_threshold <- fread("minor_sites_100x_all_20220507.csv") %>% 
#   mutate(MCoVNumber=regmatches(name, 
#                                regexpr("[M,R,S,O]CoV.[0-9]+", name)) %>% 
#            str_remove("-") %>% str_remove("_")) %>% 
#   filter(MCoVNumber %in% mcov_samples_filtered$MCoVNumber) %>%
#   filter(totalcount>=depth_at_site) %>%
#   filter(!ntpos %in% c(1:265)) %>% filter(!ntpos>29674) %>% #don't include 5' and 3' UTR
#   filter(!ntpos %in% primer_positions_all) %>% #don't include primer binding sites
#   filter(major %in% c("A","C","T","G")) %>% #don't want minor variants at consensus deletion sites
#   filter(minorfreq>=minor_frequency) %>%
#   filter(minorfreq*totalcount>=total_minor_reads) 
# write_feather(minor_variant_sites_threshold, 'processing/minor_variants_filtered_100x0.01_50.arrow')

Overall minor variant richness

source("./scripts/startup.R")
The following packages have been unloaded:
broom, tableone, arrow, magrittr, scales, lubridate, ggExtra, ggsci, pheatmap, Biostrings, GenomeInfoDb, XVector, IRanges, S4Vectors, BiocGenerics, ggrepel, data.table, ggpubr, viridis, viridisLite, gggenes, ggforce, glmnet, Matrix, cowplot, forcats, stringr, dplyr, purrr, readr, tidyr, tibble, ggplot2, tidyverse, pacman

Loading required package: pacman
minor_variant_sites_threshold <- read_feather('processing/minor_variants_filtered_100x0.01_50.arrow') 
n_var <- minor_variant_sites_threshold %>% group_by(MCoVNumber) %>% tally() %>% arrange(desc(n)) #this tally doesn't include any samples with 0 variants, so need to join to original list
samples_n_var <- mcov_samples_filtered %>% left_join(n_var) %>% 
  arrange(COLLECTION_DT) %>% mutate(n_var=tidyr::replace_na(n,0))
Joining, by = "MCoVNumber"
write_feather(samples_n_var, "processing/samples_n_var.arrow")

#what's the distribution of minor variant richness?
### 
((
  n_var_select <- samples_n_var %>% ggplot(aes(x=n_var)) + 
  geom_histogram(binwidth=5) + theme_pubr() + 
  xlab("No. minor variants in sample") + ylab("No. samples") + 
  scale_y_continuous(trans='log1p', breaks=c(1, 10, 100, 1000, 5000))
))

#what's the relationship between minor variant richness and Ct value?


n_var_select_ct = samples_n_var %>% filter(INSTRUMENT_RESULT<50) %>% 
  ggplot(aes(x=INSTRUMENT_RESULT, y=n_var)) + 
  geom_point(shape = 1, alpha = 1/8) + 
  geom_density_2d(alpha = 1/2, color = "red") + 
  scale_y_continuous(trans = "log1p", breaks = c(0,1,5,10,30,50,100,300,500)) +
  scale_x_continuous(breaks = seq(0,40,by = 5)) +
  theme_pubr() + xlab("Ct value") + ylab("n_var") +
  geom_hline(yintercept = 30, linetype = "dashed") + 
  geom_vline(xintercept = 26, linetype = "dashed")

plot1_target = ggMarginal(n_var_select_ct, type = "violin", draw_quantiles = 
             c(.25,.5,.75))

ggsave("ggsave/plot1_target.pdf", plot = plot1_target, height = 3, width = 4)

((
n_var_select_ct_filtered = samples_n_var %>% 
  filter(INSTRUMENT_RESULT<26 & n_var < 30) %>% 
  ggplot(aes(x=INSTRUMENT_RESULT, y=n_var)) + 
  geom_point(shape = 1, alpha = 1/16) + 
  geom_density_2d(color = "salmon") + 
  scale_y_continuous(breaks = seq(0,30,5)) +
  scale_x_continuous(breaks = seq(0,40,by = 5)) +
  theme_pubr() + xlab("Ct value") + ylab("n_var") +
  geom_smooth(color = "red") + stat_cor(method = "spearman", cor.coef.name = "rho")
))


patient_ordinal_counts = samples_n_var %>% 
  filter(INSTRUMENT_RESULT<26 & n_var < 30) %>% 
  mutate(ordinal_counts = cut(n_var, breaks = seq(0,30,5), 
                              right = F)) %>% 
  select(n_var, ordinal_counts) %>% arrange(n_var) %>% 
  group_by(ordinal_counts) %>% summarize(counts = n()) %>% 
  mutate(position = seq(2.5,27.5,5))

n_var_select_ct_filtered_labeled = n_var_select_ct_filtered +
  geom_text(aes(x=25, y = position, label = counts), color = "darkblue", 
                                     data = patient_ordinal_counts) +
  theme_minimal_hgrid()

ct_n_var_postfilter_plot = ggMarginal(n_var_select_ct_filtered_labeled, 
                                      type = "violin", 
                                      draw_quantiles = c(0.25,0.5,0.75))
`geom_smooth()` using method = 'gam' and formula = 'y ~ s(x, bs = "cs")'`geom_smooth()` using method = 'gam' and formula = 'y ~ s(x, bs = "cs")'
ct_n_var_postfilter_plot
# Quantile information for the violin plot above
print(samples_n_var %>% 
  filter(INSTRUMENT_RESULT<26 & n_var < 30) %>% pull(n_var) %>% quantile(.,probs = c(0,0.25,0.5,0.75)))
 0% 25% 50% 75% 
  0   2   4   8 
print(samples_n_var %>% 
  filter(INSTRUMENT_RESULT<26 & n_var < 30) %>% pull(INSTRUMENT_RESULT) %>% quantile(.,probs = c(0,0.25,0.5,0.75)))
   0%   25%   50%   75% 
 6.67 15.80 18.42 21.39 
samples_n_var %>% pull(n_var) %>% summary()
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
   0.00    3.00    6.00   18.46   15.00  449.00 

Reproducibility of minor variants

minors_table<- fread("replicated_samples.csv", data.table=F) %>% 
  filter(MCoVNumber %in% samples_n_var$MCoVNumber) %>% 
  filter(major.original %in% c("A","C","T","G")) %>% 
  filter(minor.original %in% c("A","C","T","G")) %>%
  filter(totalcount.original>=100 & minorfreq.original>=0.01 & totalcount.original*minorfreq.original>=50 & 
           tolower(binocheck.original)!="false") %>% filter((!ntpos %in% primer_positions_all)) %>% 
  filter(!ntpos %in% 1:265) %>% filter(!ntpos>29674)
|--------------------------------------------------|
|==================================================|
#was the same minor variant found in the second replicate? if not, set minor frequency to 0 in second rep
minors_table<-minors_table %>% 
  mutate(minorfreq.reseq=if_else(minor.original==minor.reseq, minorfreq.reseq, 0)) %>% 
  mutate(detected_minor_in_repl=if_else(minor.original==minor.reseq,"yes","no"))

write_feather(minors_table, "processing/minors_table.arrow")
#how well are minor variants recovered in samples with different Ct values?
minors_table <- minors_table %>% left_join(select(mcov_samples, MCoVNumber, CT=INSTRUMENT_RESULT)) %>% 
  mutate(sampleCT_bin = case_when(CT<26 ~ "below 26",
                                CT>=26&CT<=35 ~"CT 26-35",
                                CT>35&CT<50 ~"greater than 35",
                                CT>100~"unknown", #aptima instrument uses RLU not CT
                                is.na(CT) ~ "unknown")) 
Joining, by = "MCoVNumber"
((
  rep_ct<-minors_table %>% 
  ggplot(aes(x=minorfreq.original, y=minorfreq.reseq, color=detected_minor_in_repl)) + 
  scale_color_manual(values=c("red","black")) + geom_point(alpha=0.5) + 
  facet_wrap(~sampleCT_bin) + theme_bw() + labs(x="MAF in replicate 1", y="MAF in replicate 2") + 
  theme(legend.position="bottom")
))

#how well are minor variants recovered in samples with different median coverage?
rep_depth <- minors_table %>% left_join(coverage_levels, by=c("MCoVNumber"="samplename")) %>% 
  mutate(coverage_bin=cut(median_coverage, 4)) %>% 
  ggplot(aes(x=minorfreq.original, y=minorfreq.reseq, color=detected_minor_in_repl)) + 
  scale_color_manual(values=c("red","black")) + geom_point(alpha=0.5) + 
  facet_wrap(~coverage_bin) + theme_bw() + 
  labs(x="MAF in replicate 1", y="MAF in replicate 2") + 
  theme(legend.position="none", axis.text.x = element_text(color=c(1,0,1,0))) + 
  labs(caption="Reproducibility in samples with different median depths")
Warning: Vectorized input to `element_text()` is not officially supported.
ℹ Results may be unexpected or may change in future versions of ggplot2.
#in the range of Ct values/coverage observed here, reproducibility seems more associated with Ct than with coverage 
#what's the distribution of depth/MAF in reproducible vs. non-reproducible minor variants?
rep_depth_freq <- minors_table %>% ggplot(aes(x=totalcount.original, y=minorfreq.original)) + 
  geom_point(alpha=0.5) + facet_grid(detected_minor_in_repl~.) + theme_bw() + 
  theme(axis.text.x = element_text(color=c(1,0,1,0))) + xlab("Seq depth in rep 1") + 
  ylab("MAF in rep 1") + labs(caption="Reproducibility at sites with different depth and MAF")
Warning: Vectorized input to `element_text()` is not officially supported.
ℹ Results may be unexpected or may change in future versions of ggplot2.
#depth and frequency of minor variants is also not very different between reproducible and non-reproducible variants
rep_mutations <- minors_table %>% filter(detected_minor_in_repl=="yes") 
nonrep_mutations <- minors_table %>% filter(detected_minor_in_repl=="no") 

plot_reproducible_spectra_heatmap <- table(rep_mutations$major.original, rep_mutations$minor.original) %>% 
  data.frame() %>% ggplot(aes(x=Var1, y=Var2, fill=Freq/sum(Freq))) + 
  geom_tile(colour = "black") + # grid colour
  scale_fill_gradient(low = "white",
                      high = "darkblue") +
  theme_minimal() + labs(fill = "Fraction",
       x = "Consensus allele",
       y = "Minor allele", title="Reproducible")


plot_nonreproducible_spectra_heatmap <- table(nonrep_mutations$major.original,
                                              nonrep_mutations$minor.original) %>% 
  data.frame() %>% ggplot(aes(x=Var1, y=Var2, fill=Freq/sum(Freq))) + 
  geom_tile(colour = "black") + 
  scale_fill_gradient(low = "white",
                      high = "darkblue") +
  theme_minimal() + labs(fill = "Fraction",
       x = "Consensus allele",
       y = "Minor allele", title="Non-reproducible")

saveRDS(plot_nonreproducible_spectra_heatmap, file = "plot_nonreproducible_spectra_heatmap.rds")
saveRDS(plot_reproducible_spectra_heatmap, file = "plot_reproducible_spectra_heatmap.rds")

# Plotted in RMD 03.
rep_indiv_samples <- minors_table %>% ggplot(aes(x=minorfreq.original, 
                                               y=minorfreq.reseq, 
                                               color=detected_minor_in_repl)) + 
  geom_point(alpha=0.5) + scale_color_manual(values=c("red","black")) + 
  facet_wrap(CT~MCoVNumber) + theme_bw() + xlab("MAF in replicate 1") + 
  ylab("MAF in replicate 2") + 
  theme(legend.position="none", axis.text.x = element_text(color=c(1,0,1,0)))
Warning: Vectorized input to `element_text()` is not officially supported.
ℹ Results may be unexpected or may change in future versions of ggplot2.
#SUPP FIG 1
replicate_mega_plot = plot_grid(
  plot_grid(rep_ct, 
            plot_grid(rep_depth, rep_depth_freq, ncol=2, rel_widths=c(1.2,1), 
                      labels=c("b","c")), nrow=2, labels=c("a",NA)), 
  rep_indiv_samples, labels=c(NA, "d"), rel_widths=c(1.1,1))
Warning: Removed 1 rows containing missing values (`geom_text()`).
ggsave("ggsave/replicate_mega_plot.pdf", plot = replicate_mega_plot, height = 8, width = 14.5)

Will limit analyses to samples with CT<26, where we are more confident in reproducibility of minor variant

samples_n_var %>% filter(INSTRUMENT_RESULT<26 & n_var < 30) %>% pull(n_var) %>% quantile(c(0.5,0.7))
50% 70% 
  4   7 
samples_to_analyze <- samples_n_var %>% filter(INSTRUMENT_RESULT<26 & n_var < 30) %>% pull(MCoVNumber)
lineages_figure <- mcov_samples_filtered %>% 
  filter(MCoVNumber %in% samples_to_analyze) %>% 
  mutate(variant=case_when(startsWith(scorpio_call,"Delta") ~ "Delta",
        startsWith(scorpio_call,"Alpha") ~ "Alpha",
        !(startsWith(scorpio_call,"Delta")|
            startsWith(scorpio_call,"Alpha")) ~ "other")) %>%
  mutate(variant=if_else(lineage == "B.1.2","B.1.2",variant)) %>%
  mutate(month = floor_date(COLLECTION_DT, "month")) %>%
  ggplot(aes(x=month)) + geom_bar(aes(fill=variant))  + 
#  scale_fill_manual(values=c("#00A08A", "#F2AD00", "#F98400", "#5BBCD6")) + 
  xlab("Collection date") + ylab("No. samples") +   scale_x_date(labels = date_format("%m-%Y")) +
  ggtitle(paste0('Final sample set, \n Ct<26 & n_var<30, n = ',length(samples_to_analyze))) + 
  scale_x_date(minor_breaks="1 month") + theme_pubr() +
  theme(axis.text.x = element_text(angle = 90, vjust = .5), legend.position = "top")
Scale for x is already present.
Adding another scale for x, which will replace the existing scale.
#SUPP FIG 2
lineages_figure
saveRDS(lineages_figure, "ggsave/lineages_figure.rds")
ggsave("ggsave/lineages_figure.pdf", plot = lineages_figure, height = 4, width = 5)

samples_n_var %>% filter(INSTRUMENT_RESULT<26) %>% pull(n_var) %>% summary()
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
   0.00    2.00    5.00   10.44   10.00  366.00 
#plot_grid(coverage_pre_filtering, ct_inclusion, ncol=2, labels=c("a","b"))
minor_sites_lowct<-minor_variant_sites_threshold %>% left_join(mcov_samples_filtered) %>% 
  filter(INSTRUMENT_RESULT<26) 
Joining, by = "MCoVNumber"

What kinds of run-specific effects do we see even after filtering for high-quality samples?

#are run effects related to sequencing depth?
n_var_by_coverage<-samples_n_var %>% filter(INSTRUMENT_RESULT<26 & n_var < 30) %>% ggplot(aes(x=median_coverage, y=n_var)) + geom_point(alpha=0.05) + 
  geom_density_2d(color = "salmon") + geom_smooth(color = "red") + theme_pubr() +
  scale_x_continuous(limits = c(0, 15000)) +
  xlab("Sample median coverage") + ylab("n_var") + stat_cor(method = "spearman", cor.coef.name = "rho")
n_var_by_coverage

#not on the individual sample level

#is average minor variant richness in a run related to average depth of coverage in the run?
n_var_depth_averages<-samples_n_var %>% filter(INSTRUMENT_RESULT<26 & n_var < 30) %>% 
  group_by(run) %>% 
  summarise(median_n_var=median(n_var), 
            median_sample_coverage=median(median_coverage), 
            median_ct=median(INSTRUMENT_RESULT)) %>% 
  ggplot(aes(x=median_sample_coverage, y=median_n_var)) + geom_point(alpha = 0.5) +
  scale_x_continuous(limits = c(0, 15000)) +
  theme_pubr() + xlab("Run median of median coverage") + ylab("Run median n_var") + 
  geom_smooth(color = "red") + stat_cor(method = "spearman", cor.coef.name = "rho")
n_var_depth_averages

n_var_by_run <- samples_n_var %>% mutate(run = as.numeric(str_remove(run, "Run_"))) %>% 
  filter(INSTRUMENT_RESULT < 26 & n_var < 30) %>% 
    ggplot(aes(x=run, y=n_var, group = run)) + geom_boxplot() + 
    scale_fill_grey(start = 1, end = 0.8) + 
    scale_x_continuous(breaks = seq(10,90,2), limits = c(10,92), labels = label_at(10)) +
    scale_y_continuous(breaks = seq(0,30,2), labels = label_at(10)) +

    scale_color_grey(start=0, end=0.6) + 
    theme(axis.text.x = element_text(angle = 90, vjust = .5))

plots_by_run = ggarrange(f3, f4, n_var_by_run, labels = list("A","B","D"), 
          ncol = 1, nrow = 3, align = "v", common.legend = T) %>% annotate_figure(.,
               top = text_grob("red circles: samples Ct>40", color = "red", size = 10))

dots_depth_median = ggarrange(n_var_by_coverage, n_var_depth_averages,  
                              labels = list("E", "F"), ncol = 1)
Warning: Removed 4 rows containing non-finite values (`stat_density2d()`).`geom_smooth()` using method = 'gam' and formula = 'y ~ s(x, bs = "cs")'Warning: Removed 4 rows containing non-finite values (`stat_smooth()`).Warning: Removed 4 rows containing non-finite values (`stat_cor()`).Warning: Removed 4 rows containing missing values (`geom_point()`).`geom_smooth()` using method = 'loess' and formula = 'y ~ x'
dots_plots = ggarrange(runs_samples_dots, dots_depth_median, labels = list("C"), 
                       ncol = 1, heights = c(1,1))

run_filtration = ggarrange(plots_by_run, dots_plots, ncol = 2, widths = c(2.5, 1))
run_filtration

ggsave("ggsave/run_filtration.pdf", run_filtration, height = 8, width = 12)
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQKICBodG1sX2RvY3VtZW50OgogICAgZGZfcHJpbnQ6IHBhZ2VkCiAgcGRmX2RvY3VtZW50OiBkZWZhdWx0Ci0tLQoKIyBXaXRoaW4taG9zdCBkaXZlcnNpdHkgYW5kIG1pbm9yIHZhcmlhbnQgYW5hbHlzZXMgaW4gc2FtcGxlcyBmcm9tIEhvdXN0b24gTWV0aG9kaXN0IEhvc3BpdGFsLCAyMDIxCgojIyBTYW1wbGUgY2hhcmFjdGVyaXN0aWNzIGFuZCBpbmNsdXNpb24gY3JpdGVyaWEgCgoKYGBge3J9CnNvdXJjZSgiLi9zY3JpcHRzL3N0YXJ0dXAuUiIpCgojIyMjIyBMb2FkIGxpYnJhcmllcyBhbmQgZGVmaW5lIHJlY3VycmluZyBmdW5jdGlvbnMgLyB2YXJpYWJsZXMKI2FsbCBtY292IHNhbXBsZXMgd2UgaGF2ZSBldmVyIHJlY2VpdmVkIC0gcmVmb3JtYXQgc2FtcGxlIG5hbWVzIHRvIGJlIGNvbnNpc3RlbnQKbWNvdl9zYW1wbGVzX2FsbCA8LSBmcmVhZCgiZnVsbF9saW5lYWdlX3JlcG9ydF8yMDIyMDUwNy50c3YiLCBkYXRhLnRhYmxlPUYpICU+JSAKICBtdXRhdGUoTUNvVk51bWJlcj1tY292X3JlZm9ybWF0KHRheG9uKSkgJT4lIAogIGZpbHRlcihzdGFydHNXaXRoKE1Db1ZOdW1iZXIsICJNQ29WIikpICU+JSAKICBmaWx0ZXIoTUNvVk51bWJlciE9Ik1Db1YzMDkwNCIpICNyZW1vdmUgb25lIHNhbXBsZSB3aXRoIGluY29uc2lzdGVudGx5IGZvcm1hdHRlZCBkdXBsaWNhdGVzCgojcnVuIGFuZCBkYXRlIGluZm87IGtlZXAgb25seSBlYXJsaWVzdCBzYW1wbGUgZnJvbSB0aGUgc2FtZSBwYXRpZW50Cm1jb3ZfaW5mbyA8LSBmcmVhZCgic2FtcGxlX2RhdGVfYW5kX3J1bi5jc3YiLCBkYXRhLnRhYmxlPUYpICU+JSAKICBtdXRhdGUoQ09MTEVDVElPTl9EVD1hcy5EYXRlKENPTExFQ1RJT05fRFQsICIlbS8lZC8leSIpLAogICAgICAgICBNQ29WTnVtYmVyPXN0cl9yZW1vdmUobWNvdl9pZCwgIi0iKSkgJT4lCiAgYXJyYW5nZShDT0xMRUNUSU9OX0RUKSAlPiUgZmlsdGVyKCFkdXBsaWNhdGVkKFBhdGllbnRJRCkpCgojc2FtcGxlcyB3ZSByZWNlaXZlZCB0aGF0IHdlJ3JlIGludGVyZXN0ZWQgaW4gKERlY2VtYmVyIDIwMjAtTm92ZW1iZXIgMjAyMSkKbWNvdl9zYW1wbGVzXzEgPC0gbWNvdl9zYW1wbGVzX2FsbCAlPiUgZmlsdGVyKCF0YXhvbiAlaW4lIGR1cDY1LjY2KSAlPiUgCiAgZmlsdGVyKE1Db1ZOdW1iZXIgJWluJSBtY292X2luZm8kTUNvVk51bWJlcikgJT4lIGxlZnRfam9pbihtY292X2luZm8pCgojYWxsIHNhbXBsZXMgc2VxdWVuY2VkIGluIGVhY2ggcnVuIChpbmNsdWRpbmcgdGhvc2UgZnJvbSBvdXRzaWRlIG9mIHRoaXMgc3R1ZHkgcGVyaW9kKSAtLSBzb21ldGltZXMgcmVsZXZhbnQgZm9yIHJ1biBRQyBwdXJwb3NlcwpydW5zX2FsbF9zYW1wbGVzIDwtIGZyZWFkKCJydW5fc2FtcGxlcy5jc3YiLCBkYXRhLnRhYmxlID0gRikgJT4lIAogIG11dGF0ZShNQ29WTnVtYmVyPXN0cl9yZW1vdmUoYFNhbXBsZSBJRGAsIi0iKSwgcnVuPVJ1bikgJT4lIAogIHNlbGVjdChydW4sIE1Db1ZOdW1iZXIpCgojc3VtbWFyeSBzdGF0cyBvbiBjb3ZlcmFnZSBvZiBlYWNoIHNhbXBsZTsgZHJvcCB0aGUgcnVuIDY1IGR1cGxpY2F0ZXMgYW5kIGpvaW4gY292ZXJhZ2UgaW5mbyB0byBtYWluIGRhdGFzZXQKZDEgPSBmcmVhZCgnY292ZXJhZ2VfbGV2ZWxzXzIwMjIwNTA3LmNzdicsIGRhdGEudGFibGUgPSBGKSAlPiUgCiAgZmlsdGVyKGR1cGxpY2F0ZWQoc2FtcGxlbmFtZSkpICU+JSBwdWxsKHNhbXBsZW5hbWUpCmQyID0gZnJlYWQoJ2NvdmVyYWdlX2xldmVsc18yMDIyMDUwNy5jc3YnLCBkYXRhLnRhYmxlID0gRikgJT4lIAogIGZpbHRlcihzYW1wbGVuYW1lICVpbiUgZDEpICU+JSBmaWx0ZXIoIWR1cGxpY2F0ZWQoc2FtcGxlbmFtZSkpICU+JSAKICBwdWxsKGZpbGVuYW1lKQpjb3ZlcmFnZV9sZXZlbHMgPC0gZnJlYWQoJ2NvdmVyYWdlX2xldmVsc18yMDIyMDUwNy5jc3YnLCBkYXRhLnRhYmxlID0gRikgJT4lIAogIGZpbHRlcighZmlsZW5hbWUgJWluJSBkMikgJT4lIGZpbHRlcihzYW1wbGVuYW1lIT0iTUNvVjMwOTA0IikgJT4lIHNlbGVjdCgtMSkKYGBgCgpgYGB7cn0KIyBqb2luIGRhdGFmcmFtZXMKbWNvdl9zYW1wbGVzPC1tY292X3NhbXBsZXNfMSAlPiUgCiAgc2VsZWN0KE1Db1ZOdW1iZXIsIGxpbmVhZ2UsIHNjb3JwaW9fY2FsbCwgcWNfc3RhdHVzLCAKICAgICAgICAgQ09MTEVDVElPTl9EVCwgSU5TVFJVTUVOVCwgSU5TVFJVTUVOVF9SRVNVTFQsIHJ1bj1ydW5fZ3JvdXApICU+JSAKICBsZWZ0X2pvaW4oY292ZXJhZ2VfbGV2ZWxzLCBieT1jKCJNQ29WTnVtYmVyIj0ic2FtcGxlbmFtZSIpKQoKbWNvdl9zYW1wbGVzX3dpdGhfY3Q8LW1jb3Zfc2FtcGxlcyAlPiUgZmlsdGVyKElOU1RSVU1FTlRfUkVTVUxUPDUwKSAlPiUgCiAgbXV0YXRlKENUPUlOU1RSVU1FTlRfUkVTVUxUKQojd2hhdCdzIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBDVCB2YWx1ZSBhbmQgcmVhZCBjb3ZlcmFnZT8KY292ZXJhZ2VfYWxsPC1tY292X3NhbXBsZXNfd2l0aF9jdCAlPiUgZ2dwbG90KGFlcyh4PUNULCB5PW1lZGlhbl9jb3ZlcmFnZSkpICsgCiAgZ2VvbV9wb2ludChhbHBoYT0wLjA3KSArIHRoZW1lX2J3KCkgKyB4bGFiKCJDdCB2YWx1ZSIpICsgeWxhYigiU2FtcGxlIG1lZGlhbiBkZXB0aCIpCiNob3cgZG9lcyBjb3ZlcmFnZSBpbiBoaWdoLUNUIHNhbXBsZXMgY29tcGFyZSB3aXRoIHRoZSByZXN0IG9mIHRoZW0/CmNvdmVyYWdlX2N0X2NhdDwtbWNvdl9zYW1wbGVzX3dpdGhfY3QgJT4lIG11dGF0ZShzYW1wbGVfY3Q9aWZfZWxzZShDVD49NDAsICJDVD49NDAiLCAiQ1Q8NDAiKSkgJT4lIAogIGdncGxvdChhZXMoeD1zYW1wbGVfY3QsIHk9bWVkaWFuX2NvdmVyYWdlKSkgKyAKICBnZW9tX3BvaW50KGFscGhhPTAuMiwgcG9zaXRpb249cG9zaXRpb25faml0dGVyKHdpZHRoPTAuMjUpKSArIAogIGdlb21fYm94cGxvdChjb2xvcj0icmVkIiwgYWxwaGE9MCkgKyB0aGVtZV9idygpICsgCiAgeGxhYigiQ3QgdmFsdWUiKSArIHlsYWIoIlNhbXBsZSBtZWRpYW4gZGVwdGgiKQpgYGAKCgojIyBSdW4tbGV2ZWwgUUMgCgpgYGB7cn0KI2FyZSB0aGVyZSBhbnkgcnVucyB3aGVyZSBoaWdoLUNUIHNhbXBsZXMgaGF2ZSB1bnVzdWFsbHkgaGlnaCBjb3ZlcmFnZT8gdHJlYXQgQ1Q+NDAgc2FtcGxlcyBhcyBuZWdhdGl2ZSBjb250cm9scyBhbmQgZWxpbWluYXRlIHJ1bnMgd2hlcmUgdGhlaXIgY292ZXJhZ2UgaXMgbm90IGRpZmZlcmVudCBmcm9tIHRob3NlIG9mIHRoZSByZXN0IG9mIHRoZSBzYW1wbGVzCnRlc3RfZ3JvdXA8LW1jb3Zfc2FtcGxlc193aXRoX2N0ICU+JSBtdXRhdGUoaXNfbmVnPWlmX2Vsc2UoQ1Q+PTQwLDEsMCkpICU+JSAKICBncm91cF9ieShydW4pICU+JSBtdXRhdGUobl9uZWdzPXN1bShpc19uZWcpKSAlPiUgZmlsdGVyKG5fbmVncz49MykgJT4lIAogIHVuZ3JvdXAoKSAlPiUgbXV0YXRlKHNhbXBsZXR5cGU9aWZfZWxzZShpc19uZWc9PTEsICJuZWdjdHJsIiwic2FtcGxlIikpCnJ1bnNfdG9fZHJvcDEgPSB0ZXN0X2dyb3VwICU+JSBncm91cF9ieShydW4pICU+JSAKICBzdW1tYXJpc2UodF90ZXN0X3A9dC50ZXN0KGZyYWN0aW9uXzEwMDB4X2NvdmVyYWdlfnNhbXBsZXR5cGUpJHAudmFsdWUpICU+JSAKICBhcnJhbmdlKGRlc2ModF90ZXN0X3ApKSAlPiUgZmlsdGVyKHRfdGVzdF9wPjAuMDEpICU+JSBwdWxsKHJ1bikKcnVuc190b19kcm9wMiA9IHRlc3RfZ3JvdXAgJT4lIGdyb3VwX2J5KHJ1bikgJT4lIAogIHN1bW1hcmlzZSh0X3Rlc3RfcD10LnRlc3QobWVkaWFuX2NvdmVyYWdlfnNhbXBsZXR5cGUpJHAudmFsdWUpICU+JSAKICBhcnJhbmdlKGRlc2ModF90ZXN0X3ApKSAlPiUgZmlsdGVyKHRfdGVzdF9wPjAuMDEpICU+JSBwdWxsKHJ1bikKCiMjIyMjIyMjIyMjIyAKcnVuc190b19kcm9wPC11bmlvbihydW5zX3RvX2Ryb3AxLCBydW5zX3RvX2Ryb3AyKQpzYXZlUkRTKHJ1bnNfdG9fZHJvcCwgInByb2Nlc3NpbmcvcnVuc190b19kcm9wLnJkcyIpCgptY292X3NhbXBsZXNfd2l0aF9jdCAlPiUgcHVsbChydW4pICU+JSB1bmlxdWUoKQp0ZXN0X2dyb3VwICU+JSBncm91cF9ieShydW4sIHNhbXBsZXR5cGUpICU+JSBzdW1tYXJpemUoY291bnRzID0gbigpKSAlPiUgCiAgZmlsdGVyKHJ1biAlaW4lIHJ1bnNfdG9fZHJvcCkgJT4lIG5yb3coKQoKbWNvdl9zYW1wbGVzX3dpdGhfY3QgJT4lIHB1bGwocnVuKSAlPiUgdW5pcXVlKCkKdGVzdF9ncm91cCAlPiUgZ3JvdXBfYnkocnVuLCBzYW1wbGV0eXBlKSAlPiUgc3VtbWFyaXplKGNvdW50cyA9IG4oKSkgJT4lIAogIGZpbHRlcihzYW1wbGV0eXBlPT0ibmVnY3RybCIpICU+JSBhcnJhbmdlKGNvdW50cykgJT4lIG11dGF0ZShkcm9wcGVkID0gcnVuICVpbiUgcnVuc190b19kcm9wKSAlPiUKICBnZ3Bsb3QoYWVzKGRyb3BwZWQsY291bnRzLCBsYWJlbD1ydW4pKSArIGdlb21fYm94cGxvdCgpICsgZ2VvbV9wb2ludCgpICsgZ2VvbV90ZXh0X3JlcGVsKCkgKyB0aGVtZV9wdWJyKCkKCnJ1bnNfa2VwdCA9IG1jb3Zfc2FtcGxlc193aXRoX2N0JHJ1blshbWNvdl9zYW1wbGVzX3dpdGhfY3QkcnVuICVpbiUgcnVuc190b19kcm9wXSAlPiUgdW5pcXVlKCkKCmBgYAoKYGBge3J9CmYxID0gbWNvdl9zYW1wbGVzX3dpdGhfY3QgJT4lIG11dGF0ZShydW5fa2VwdCA9IHJ1biAlaW4lIHJ1bnNfa2VwdCkgJT4lIAogIGdncGxvdChhZXMoSU5TVFJVTUVOVF9SRVNVTFQsIGZyYWN0aW9uXzEwMDB4X2NvdmVyYWdlLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9IHJ1bl9rZXB0KSkgKyAKICBnZW9tX3BvaW50KHNoYXBlPSIuIiwgYWxwaGEgPSAwLjUpICsgdGhlbWVfcHVicigpICsgCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gNDAsIGZhY2UgPSAiYm9sZCIpKSArIAogIGdlb21fdmxpbmUoeGludGVyY2VwdD00MCwgY29sb3IgPSAicmVkIikgKyBnZW9tX3Ntb290aCgpCmYxCgpmMiA9IG1jb3Zfc2FtcGxlc193aXRoX2N0ICU+JSBtdXRhdGUocnVuX2tlcHQgPSBydW4gJWluJSBydW5zX2tlcHQpICU+JSAKICBnZ3Bsb3QoYWVzKElOU1RSVU1FTlRfUkVTVUxULCBsb2cxMChtZWRpYW5fY292ZXJhZ2UpLCBjb2xvciA9IHJ1bl9rZXB0KSkgKyAKICBnZW9tX3BvaW50KHNoYXBlPSIuIiwgYWxwaGEgPSAwLjUpICsgdGhlbWVfcHVicigpICsgCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gNDAsIGZhY2UgPSAiYm9sZCIpKSArIAogIGdlb21fdmxpbmUoeGludGVyY2VwdD00MCwgY29sb3IgPSAicmVkIikgKyBnZW9tX3Ntb290aCgpCgpydW5zX3NhbXBsZXNfZG90cyA9IGdnYXJyYW5nZShmMSwgZjIsIG5jb2wgPSAxLCBucm93ID0gMiwgYWxpZ24gPSAidiIsIGNvbW1vbi5sZWdlbmQgPSBUKQpydW5zX3NhbXBsZXNfZG90cwpnZ3NhdmUoImdnc2F2ZS9ydW5zX3NhbXBsZXNfZG90cy5wZGYiLCBwbG90ID0gcnVuc19zYW1wbGVzX2RvdHMsIHdpZHRoID0gMywgaGVpZ2h0ID0gNC41KQpgYGAKCgpgYGB7cn0KbWNvdl9zYW1wbGVzX3dpdGhfY3QgJT4lIGNvbG5hbWVzKCkKYGBgCgoKYGBge3J9CiMjIyBwbG90IGJveHBsb3Qgb2YgdGhlIHJ1bnMKc3RtcCA9IG1jb3Zfc2FtcGxlc193aXRoX2N0ICU+JSBtdXRhdGUocnVuX2Ryb3BwZWQgPSBydW4gJWluJSAgIAogICAgcnVuc190b19kcm9wKSAlPiUgbXV0YXRlKHJ1biA9IGFzLm51bWVyaWMoZ3N1YigiUnVuXyIsICIiLCBydW4pKSkgJT4lIAogICAgbXV0YXRlKGlzX25lZz1pZl9lbHNlKENUPj00MCwxLDApKQoKbGFiZWxfYXQgPC0gZnVuY3Rpb24obikgZnVuY3Rpb24oeCkgaWZlbHNlKHggJSUgbiA9PSAwLCB4LCAiIikKCgpmMyA9IGdncGxvdChzdG1wLCBhZXMoeD1ydW4sIHk9ZnJhY3Rpb25fMTAwMHhfY292ZXJhZ2UsIGdyb3VwID0gcnVuLCAKICAgICAgICAgICAgIGNvbG9yID0gcnVuX2Ryb3BwZWQsIGZpbGwgPSBydW5fZHJvcHBlZCkpICsgCiAgZ2VvbV9ib3hwbG90KCkgKyAKICBnZW9tX3BvaW50KGRhdGEgPSBzdG1wICU+JSBmaWx0ZXIoaXNfbmVnID09IFQpLCAKICAgICAgICAgICAgIGFlcyhydW4sIGZyYWN0aW9uXzEwMDB4X2NvdmVyYWdlKSwgY29sb3IgPSAicmVkIiwgYWxwaGEgPSAuOSwgCiAgICAgICAgICAgICBzaGFwZSA9IDEpICsgCiAgc2NhbGVfZmlsbF9ncmV5KHN0YXJ0ID0gMSwgZW5kID0gMC44KSArIAogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzZXEoMTAsOTAsMiksIGxpbWl0cyA9IGMoMTAsOTIpLCBsYWJlbHMgPSBsYWJlbF9hdCgxMCkpICsgIAogIHNjYWxlX2NvbG9yX2dyZXkoc3RhcnQ9MCwgZW5kPTAuNikgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHZqdXN0ID0gLjUpKSArCiAgbGFicyggeCA9IE5VTEwpCiAgCmY0ID0gZ2dwbG90KHN0bXAsIGFlcyh4PXJ1biwgeT1sb2cxMChtZWRpYW5fY292ZXJhZ2UpLCBncm91cCA9IHJ1biwgCiAgICAgICAgICAgICBjb2xvciA9IHJ1bl9kcm9wcGVkLCBmaWxsID0gcnVuX2Ryb3BwZWQpKSArIAogIGdlb21fYm94cGxvdCgpICsgCiAgZ2VvbV9wb2ludChkYXRhID0gc3RtcCAlPiUgZmlsdGVyKGlzX25lZyA9PSBUKSwgCiAgICAgICAgICAgICBhZXMocnVuLCBsb2cxMChtZWRpYW5fY292ZXJhZ2UpKSwgY29sb3IgPSAicmVkIiwgYWxwaGEgPSAuOSwgCiAgICAgICAgICAgICBzaGFwZSA9IDEpICsgCiAgc2NhbGVfZmlsbF9ncmV5KHN0YXJ0ID0gMSwgZW5kID0gMC44KSArIAogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzZXEoMTAsOTAsMiksIGxpbWl0cyA9IGMoMTAsOTIpLCBsYWJlbHMgPSBsYWJlbF9hdCgxMCkpICsgIAogIHNjYWxlX2NvbG9yX2dyZXkoc3RhcnQ9MCwgZW5kPTAuNikgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHZqdXN0ID0gLjUpKSArCiAgbGFicyggeCA9IE5VTEwpCgpydW5fZmlsdGVyX3JlZCA9IGdnYXJyYW5nZShmMywgZjQsIG5jb2wgPSAxLCBucm93ID0gMiwgYWxpZ24gPSAidiIsIGNvbW1vbi5sZWdlbmQgPSBUKQooKAogIHJ1bl9maWx0ZXJfcmVkX3Bsb3QgPSBhbm5vdGF0ZV9maWd1cmUocnVuX2ZpbHRlcl9yZWQsCiAgICAgICAgICAgICAgIHRvcCA9IHRleHRfZ3JvYigicmVkIGNpcmNsZXM6IHNhbXBsZXMgQ3Q+NDAiLCBjb2xvciA9ICJyZWQiLCBzaXplID0gMTApKQopKQoKZ2dzYXZlKCJnZ3NhdmUvcnVuX2ZpbHRlcl9yZWRfcGxvdC5wZGYiLCBwbG90ID0gcnVuX2ZpbHRlcl9yZWRfcGxvdCwgd2lkdGggPSA2LCBoZWlnaHQgPSA0KQpgYGAKCiMjIFNhbXBsZS1sZXZlbCBRQwpgYGB7cn0KI25leHRjbGFkZSBRQwpuYzwtZnJlYWQoImhvdXN0b25fbmV4dGNsYWRlLnRzdiIsIHNlcD0nXHQnLCBkYXRhLnRhYmxlID0gRikgJT4lIAogIG11dGF0ZShNQ29WTnVtYmVyPXJlZ21hdGNoZXMoc2VxTmFtZSwgcmVnZXhwcigiW00sUixTLE9dQ29WLlswLTldKyIsIHNlcU5hbWUpKSAlPiUgCiAgICAgICAgICAgc3RyX3JlbW92ZSgiLSIpICU+JSBzdHJfcmVtb3ZlKCJfIikpICU+JSBmaWx0ZXIoIWR1cGxpY2F0ZWQoTUNvVk51bWJlcikpCm5leHRjbGFkZV9iYWRfc2FtcGxlczwtbmMgJT4lIGZpbHRlcihxYy5vdmVyYWxsU3RhdHVzICVpbiUgYygiYmFkIikpICU+JSBwdWxsKE1Db1ZOdW1iZXIpCiNkcm9wIGJhZCBydW5zIGFuZCBzYW1wbGVzIHRoYXQgZG9uJ3QgcGFzcyBwYW5nb2xpbiBRQyBvciBuZXh0Y2xhZGUgUUMKbWNvdl9zYW1wbGVzX2ZpbHRlcmVkPC1tY292X3NhbXBsZXMgJT4lIGZpbHRlcighcnVuICVpbiUgcnVuc190b19kcm9wKSAlPiUgCiAgZmlsdGVyKHFjX3N0YXR1cz09InBhc3MiKSAlPiUgZmlsdGVyKCFNQ29WTnVtYmVyICVpbiUgbmV4dGNsYWRlX2JhZF9zYW1wbGVzKSAlPiUgCiAgZmlsdGVyKHNjb3JwaW9fY2FsbCE9Ik9taWNyb24gKEJBLjEtbGlrZSkiKSAlPiUgCiAjIyMjIyAjbWFpbiBjb3ZlcmFnZSBjcml0ZXJpb24gZm9yIGZhaXIgY29tcGFyaXNvbnM6IFggZGVwdGggb3ZlciBZIHBlcmNlbnQgb2YgdGhlIGdlbm9tZQogIGZpbHRlcihmcmFjdGlvbl8xMDB4X2NvdmVyYWdlPj0wLjk4KSAlPiUgZHJvcGxldmVscygpCgojd2hhdCdzIHRoZSBkaXN0cmlidXRpb24gb2YgQ1QgdmFsdWVzPwpjdF9kaXN0cmlidXRpb25fYWZ0ZXJfcWM8LW1jb3Zfc2FtcGxlc19maWx0ZXJlZCAlPiUgZmlsdGVyKElOU1RSVU1FTlRfUkVTVUxUPDUwKSAlPiUgCiAgZ2dwbG90KGFlcyh4PUlOU1RSVU1FTlRfUkVTVUxUKSkgKyBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aD0xKSArIHRoZW1lX2J3KCkgKyAKICB4bGFiKCJDdCB2YWx1ZSIpICsgbGFicyhjYXB0aW9uPSJBZnRlciBleGNsdXNpb24gY3JpdGVyaWEiKQpgYGAKCmBgYHtyfQojSG93IGRpZCBleGNsdXNpb24gY3JpdGVyaWEgY2hhbmdlIGRpc3RyaWJ1dGlvbiBvZiBzYW1wbGUgQ3QgdmFsdWVzPwoKY3RfZGlzdHJpYnV0aW9uX2FmdGVyX3FjPC1tY292X3NhbXBsZXNfZmlsdGVyZWQgJT4lIGZpbHRlcihJTlNUUlVNRU5UX1JFU1VMVDw1MCkgJT4lIGdncGxvdChhZXMoeD1JTlNUUlVNRU5UX1JFU1VMVCkpICsgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGg9MSkgKyB0aGVtZV9idygpICsgeGxhYigiQ3QgdmFsdWUiKQoKY3RfZGlzdHJpYnV0aW9uX2JlZm9yZV9xYzwtbWNvdl9zYW1wbGVzICU+JSBmaWx0ZXIoSU5TVFJVTUVOVF9SRVNVTFQ8NTApICU+JSBnZ3Bsb3QoYWVzKHg9SU5TVFJVTUVOVF9SRVNVTFQpKSArIGdlb21faGlzdG9ncmFtKGJpbndpZHRoPTEpICsgdGhlbWVfYncoKSArIHhsYWIoIkN0IHZhbHVlIikgKyBsYWJzKGNhcHRpb249IkJlZm9yZSBleGNsdXNpb24gY3JpdGVyaWEiKQojY3RfaW5jbHVzaW9uPC1wbG90X2dyaWQoY3RfZGlzdHJpYnV0aW9uX2JlZm9yZV9xYywgY3RfZGlzdHJpYnV0aW9uX2FmdGVyX3FjLCBucm93PTIpCgojY3RfaW5jbHVzaW9uCgoKY3RfZGlzdHJpYnV0aW9uX2FmdGVyX3FjPC1tY292X3NhbXBsZXNfZmlsdGVyZWQgJT4lIGZpbHRlcihJTlNUUlVNRU5UX1JFU1VMVDw1MCkKY3RfZGlzdHJpYnV0aW9uX2JlZm9yZV9xYzwtbWNvdl9zYW1wbGVzICU+JSBmaWx0ZXIoSU5TVFJVTUVOVF9SRVNVTFQ8NTApCnBsb3QxX2N0X2JlZm9yZV9hZnRlciA9IGdncGxvdChhZXMoeD1JTlNUUlVNRU5UX1JFU1VMVCksIGRhdGEgPSBjdF9kaXN0cmlidXRpb25fYmVmb3JlX3FjKSArIAogIGdlb21faGlzdG9ncmFtKGJpbndpZHRoID0gMSwgZmlsbCA9ICJncmV5IikgKwogIGdlb21faGlzdG9ncmFtKGRhdGEgPSBjdF9kaXN0cmlidXRpb25fYWZ0ZXJfcWMsIGJpbndpZHRoPTEpICsgdGhlbWVfcHVicigpICsgCiAgeGxhYigiQ3QgdmFsdWUiKSArIHlsYWIoIiMgc2FtcGxlcyIpICMrIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDI2LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgICAgIGxpbmV0eXBlID0gImRhc2hlZCIpCgpnZ3NhdmUoImdnc2F2ZS9wbG90MV9jdF9iZWZvcmVfYWZ0ZXIucGRmIiwgcGxvdDFfY3RfYmVmb3JlX2FmdGVyLCBoZWlnaHQgPSAyLCB3aWR0aCA9IDQpCmBgYAoKIyMgUHJlbGltaW5hcnkgbWlub3IgdmFyaWFudCBkaXN0cmlidXRpb25zCgpgYGB7cn0KI251Y2xlb3RpZGUgcG9zaXRpb25zIG9mIGFsbCBwcmltZXJzIHVzZWQgaW4gZGF0YXNldDsgd2lsbCBleGNsdWRlIApwcmltZXJzID0gZnJlYWQoIm5Db1YtMjAxOS5hcnRpY192My5wcmltZXIudHh0Iiwgc2VwPSJcdCIsIGhlYWRlcj1GQUxTRSwgZGF0YS50YWJsZT1GKSAlPiUgCiAgc2VsZWN0KHN0YXJ0ID0gVjIsIGVuZCA9IFYzKQpwcmltZXJfcG9zaXRpb25zX3YzPC1hcy5udW1lcmljKCkKZm9yIChpIGluIDE6bnJvdyhwcmltZXJzKSl7CiAgcHJpbWVyX3Bvc2l0aW9uc192MzwtYyhwcmltZXJfcG9zaXRpb25zX3YzLCBwcmltZXJzW2ksXSRzdGFydDpwcmltZXJzW2ksXSRlbmQpCn0KCnByaW1lcnMgPSBmcmVhZCgibkNvVi0yMDE5LmFydGljX3Y0LnByaW1lci5iZWQiLCBzZXA9Ilx0IiwgCiAgICAgICAgICAgICAgICBoZWFkZXI9RkFMU0UsIGRhdGEudGFibGUgPSBGKSAlPiUgc2VsZWN0KHN0YXJ0ID0gVjIsIGVuZCA9IFYzKQpwcmltZXJfcG9zaXRpb25zX3Y0PC1hcy5udW1lcmljKCkKZm9yIChpIGluIDE6bnJvdyhwcmltZXJzKSl7CiAgcHJpbWVyX3Bvc2l0aW9uc192NDwtYyhwcmltZXJfcG9zaXRpb25zX3Y0LCBwcmltZXJzW2ksXSRzdGFydDpwcmltZXJzW2ksXSRlbmQpCn0KCnByaW1lcnMgPSBmcmVhZCgiVjQuMS5iZWQiLCBzZXA9Ilx0IiwgaGVhZGVyPUZBTFNFLCBkYXRhLnRhYmxlPUYpICU+JSAKICBzZWxlY3Qoc3RhcnQgPSBWMiwgZW5kID0gVjMpCnByaW1lcl9wb3NpdGlvbnNfdjQuMSA8LSBhcy5udW1lcmljKCkKZm9yIChpIGluIDE6bnJvdyhwcmltZXJzKSl7CiAgcHJpbWVyX3Bvc2l0aW9uc192NC4xIDwtIGMocHJpbWVyX3Bvc2l0aW9uc192NC4xLCBwcmltZXJzW2ksXSRzdGFydDpwcmltZXJzW2ksXSRlbmQpCn0KCnByb2JsZW1fc2l0ZXMgPSBmcmVhZCgicHJvYmxlbWF0aWNfc2l0ZXNfc2Fyc0NvdjJfdjgtMjAyMTEwMjcudmNmIiwgc2tpcCA9IDg4KQoKcHJpbWVyX3Bvc2l0aW9uc19hbGwgPC0gYyhwcmltZXJfcG9zaXRpb25zX3YzLCBwcmltZXJfcG9zaXRpb25zX3Y0LCBwcmltZXJfcG9zaXRpb25zX3Y0LjEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvYmxlbV9zaXRlcyRQT1MpICU+JSB1bmlxdWUoKQoKc2F2ZVJEUyhwcmltZXJfcG9zaXRpb25zX2FsbCwgInByaW1lcl9wb3NpdGlvbnNfYWxsLnJkcyIpCgojcmVmZXJlbmNlIGdlbm9tZSB3aXRoIG51Y2xlb3RpZGUgcG9zaXRpb25zIG9mIGdlbmVzCmdlbmVzIDwtIGZyZWFkKCJudHBvc19nZW5lX3VwZGF0ZS5jc3YiLCBkYXRhLnRhYmxlID0gRikKZ2VuZV9uYW1lcyA8LSBnZW5lcyAlPiUgcHVsbChnZW5lX2lkKSAlPiUgdW5pcXVlKCkKZ2VuZXMkZ2VuZV9pZCA8LSBmYWN0b3IoZ2VuZXMkZ2VuZV9pZCwgbGV2ZWxzID0gZ2VuZV9uYW1lcykKYGBgCgpgYGB7cn0KIyMjIFVwZGF0ZSB0aGlzIGlmIHlvdSBjaGFuZ2Ugc2FtcGxlIGluY2x1c2lvbiBjcml0ZXJpYQojIyMgVXBkYXRlIHRoaXMgaWYgY2hhbmdlIHRoZSB0aHJlc2hvbGRzIGZvciBjb3VudGluZyBtaW5vciB2YXJpYW50cwojZmlsZSB3YXMgYWxyZWFkeSBmaWx0ZXJlZCB0byBzaXRlcyB3aXRoIG1pbmltdW0gMTAwIHJlYWRzIGRlcHRoIGFuZCBBLEMsVCxHIG1pbm9yIHZhcmlhbnQgcHJlc2VudCBhbmQgYmlub21pYWwgc2lnbmlmaWNhbmNlIGNoZWNrIHBhc3NlZC4gRnVydGhlciBmaWx0ZXJpbmc6CgoKIyBkZXB0aF9hdF9zaXRlPC0xMDAKIyBtaW5vcl9mcmVxdWVuY3k8LTAuMDEKIyB0b3RhbF9taW5vcl9yZWFkczwtNTAKIyAjCiMgbWlub3JfdmFyaWFudF9zaXRlc190aHJlc2hvbGQgPC0gZnJlYWQoIm1pbm9yX3NpdGVzXzEwMHhfYWxsXzIwMjIwNTA3LmNzdiIpICU+JSAKIyAgIG11dGF0ZShNQ29WTnVtYmVyPXJlZ21hdGNoZXMobmFtZSwgCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlZ2V4cHIoIltNLFIsUyxPXUNvVi5bMC05XSsiLCBuYW1lKSkgJT4lIAojICAgICAgICAgICAgc3RyX3JlbW92ZSgiLSIpICU+JSBzdHJfcmVtb3ZlKCJfIikpICU+JSAKIyAgIGZpbHRlcihNQ29WTnVtYmVyICVpbiUgbWNvdl9zYW1wbGVzX2ZpbHRlcmVkJE1Db1ZOdW1iZXIpICU+JQojICAgZmlsdGVyKHRvdGFsY291bnQ+PWRlcHRoX2F0X3NpdGUpICU+JQojICAgZmlsdGVyKCFudHBvcyAlaW4lIGMoMToyNjUpKSAlPiUgZmlsdGVyKCFudHBvcz4yOTY3NCkgJT4lICNkb24ndCBpbmNsdWRlIDUnIGFuZCAzJyBVVFIKIyAgIGZpbHRlcighbnRwb3MgJWluJSBwcmltZXJfcG9zaXRpb25zX2FsbCkgJT4lICNkb24ndCBpbmNsdWRlIHByaW1lciBiaW5kaW5nIHNpdGVzCiMgICBmaWx0ZXIobWFqb3IgJWluJSBjKCJBIiwiQyIsIlQiLCJHIikpICU+JSAjZG9uJ3Qgd2FudCBtaW5vciB2YXJpYW50cyBhdCBjb25zZW5zdXMgZGVsZXRpb24gc2l0ZXMKIyAgIGZpbHRlcihtaW5vcmZyZXE+PW1pbm9yX2ZyZXF1ZW5jeSkgJT4lCiMgICBmaWx0ZXIobWlub3JmcmVxKnRvdGFsY291bnQ+PXRvdGFsX21pbm9yX3JlYWRzKSAKIyB3cml0ZV9mZWF0aGVyKG1pbm9yX3ZhcmlhbnRfc2l0ZXNfdGhyZXNob2xkLCAncHJvY2Vzc2luZy9taW5vcl92YXJpYW50c19maWx0ZXJlZF8xMDB4MC4wMV81MC5hcnJvdycpCmBgYAoKCgojIyBPdmVyYWxsIG1pbm9yIHZhcmlhbnQgcmljaG5lc3MKCmBgYHtyfQpzb3VyY2UoIi4vc2NyaXB0cy9zdGFydHVwLlIiKQptaW5vcl92YXJpYW50X3NpdGVzX3RocmVzaG9sZCA8LSByZWFkX2ZlYXRoZXIoJ3Byb2Nlc3NpbmcvbWlub3JfdmFyaWFudHNfZmlsdGVyZWRfMTAweDAuMDFfNTAuYXJyb3cnKSAKbl92YXIgPC0gbWlub3JfdmFyaWFudF9zaXRlc190aHJlc2hvbGQgJT4lIGdyb3VwX2J5KE1Db1ZOdW1iZXIpICU+JSB0YWxseSgpICU+JSBhcnJhbmdlKGRlc2MobikpICN0aGlzIHRhbGx5IGRvZXNuJ3QgaW5jbHVkZSBhbnkgc2FtcGxlcyB3aXRoIDAgdmFyaWFudHMsIHNvIG5lZWQgdG8gam9pbiB0byBvcmlnaW5hbCBsaXN0CnNhbXBsZXNfbl92YXIgPC0gbWNvdl9zYW1wbGVzX2ZpbHRlcmVkICU+JSBsZWZ0X2pvaW4obl92YXIpICU+JSAKICBhcnJhbmdlKENPTExFQ1RJT05fRFQpICU+JSBtdXRhdGUobl92YXI9dGlkeXI6OnJlcGxhY2VfbmEobiwwKSkKd3JpdGVfZmVhdGhlcihzYW1wbGVzX25fdmFyLCAicHJvY2Vzc2luZy9zYW1wbGVzX25fdmFyLmFycm93IikKCiN3aGF0J3MgdGhlIGRpc3RyaWJ1dGlvbiBvZiBtaW5vciB2YXJpYW50IHJpY2huZXNzPwojIyMgCigoCiAgbl92YXJfc2VsZWN0IDwtIHNhbXBsZXNfbl92YXIgJT4lIGdncGxvdChhZXMoeD1uX3ZhcikpICsgCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGg9NSkgKyB0aGVtZV9wdWJyKCkgKyAKICB4bGFiKCJOby4gbWlub3IgdmFyaWFudHMgaW4gc2FtcGxlIikgKyB5bGFiKCJOby4gc2FtcGxlcyIpICsgCiAgc2NhbGVfeV9jb250aW51b3VzKHRyYW5zPSdsb2cxcCcsIGJyZWFrcz1jKDEsIDEwLCAxMDAsIDEwMDAsIDUwMDApKQopKQpgYGAKCmBgYHtyfQojd2hhdCdzIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBtaW5vciB2YXJpYW50IHJpY2huZXNzIGFuZCBDdCB2YWx1ZT8KCgpuX3Zhcl9zZWxlY3RfY3QgPSBzYW1wbGVzX25fdmFyICU+JSBmaWx0ZXIoSU5TVFJVTUVOVF9SRVNVTFQ8NTApICU+JSAKICBnZ3Bsb3QoYWVzKHg9SU5TVFJVTUVOVF9SRVNVTFQsIHk9bl92YXIpKSArIAogIGdlb21fcG9pbnQoc2hhcGUgPSAxLCBhbHBoYSA9IDEvOCkgKyAKICBnZW9tX2RlbnNpdHlfMmQoYWxwaGEgPSAxLzIsIGNvbG9yID0gInJlZCIpICsgCiAgc2NhbGVfeV9jb250aW51b3VzKHRyYW5zID0gImxvZzFwIiwgYnJlYWtzID0gYygwLDEsNSwxMCwzMCw1MCwxMDAsMzAwLDUwMCkpICsKICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsNDAsYnkgPSA1KSkgKwogIHRoZW1lX3B1YnIoKSArIHhsYWIoIkN0IHZhbHVlIikgKyB5bGFiKCJuX3ZhciIpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAzMCwgbGluZXR5cGUgPSAiZGFzaGVkIikgKyAKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAyNiwgbGluZXR5cGUgPSAiZGFzaGVkIikKCnBsb3QxX3RhcmdldCA9IGdnTWFyZ2luYWwobl92YXJfc2VsZWN0X2N0LCB0eXBlID0gInZpb2xpbiIsIGRyYXdfcXVhbnRpbGVzID0gCiAgICAgICAgICAgICBjKC4yNSwuNSwuNzUpKQoKZ2dzYXZlKCJnZ3NhdmUvcGxvdDFfdGFyZ2V0LnBkZiIsIHBsb3QgPSBwbG90MV90YXJnZXQsIGhlaWdodCA9IDMsIHdpZHRoID0gNCkKCigoCm5fdmFyX3NlbGVjdF9jdF9maWx0ZXJlZCA9IHNhbXBsZXNfbl92YXIgJT4lIAogIGZpbHRlcihJTlNUUlVNRU5UX1JFU1VMVDwyNiAmIG5fdmFyIDwgMzApICU+JSAKICBnZ3Bsb3QoYWVzKHg9SU5TVFJVTUVOVF9SRVNVTFQsIHk9bl92YXIpKSArIAogIGdlb21fcG9pbnQoc2hhcGUgPSAxLCBhbHBoYSA9IDEvMTYpICsgCiAgZ2VvbV9kZW5zaXR5XzJkKGNvbG9yID0gInNhbG1vbiIpICsgCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLDMwLDUpKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLDQwLGJ5ID0gNSkpICsKICB0aGVtZV9wdWJyKCkgKyB4bGFiKCJDdCB2YWx1ZSIpICsgeWxhYigibl92YXIiKSArCiAgZ2VvbV9zbW9vdGgoY29sb3IgPSAicmVkIikgKyBzdGF0X2NvcihtZXRob2QgPSAic3BlYXJtYW4iLCBjb3IuY29lZi5uYW1lID0gInJobyIpCikpCgpwYXRpZW50X29yZGluYWxfY291bnRzID0gc2FtcGxlc19uX3ZhciAlPiUgCiAgZmlsdGVyKElOU1RSVU1FTlRfUkVTVUxUPDI2ICYgbl92YXIgPCAzMCkgJT4lIAogIG11dGF0ZShvcmRpbmFsX2NvdW50cyA9IGN1dChuX3ZhciwgYnJlYWtzID0gc2VxKDAsMzAsNSksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICByaWdodCA9IEYpKSAlPiUgCiAgc2VsZWN0KG5fdmFyLCBvcmRpbmFsX2NvdW50cykgJT4lIGFycmFuZ2Uobl92YXIpICU+JSAKICBncm91cF9ieShvcmRpbmFsX2NvdW50cykgJT4lIHN1bW1hcml6ZShjb3VudHMgPSBuKCkpICU+JSAKICBtdXRhdGUocG9zaXRpb24gPSBzZXEoMi41LDI3LjUsNSkpCgpuX3Zhcl9zZWxlY3RfY3RfZmlsdGVyZWRfbGFiZWxlZCA9IG5fdmFyX3NlbGVjdF9jdF9maWx0ZXJlZCArCiAgZ2VvbV90ZXh0KGFlcyh4PTI1LCB5ID0gcG9zaXRpb24sIGxhYmVsID0gY291bnRzKSwgY29sb3IgPSAiZGFya2JsdWUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGEgPSBwYXRpZW50X29yZGluYWxfY291bnRzKSArCiAgdGhlbWVfbWluaW1hbF9oZ3JpZCgpCgpjdF9uX3Zhcl9wb3N0ZmlsdGVyX3Bsb3QgPSBnZ01hcmdpbmFsKG5fdmFyX3NlbGVjdF9jdF9maWx0ZXJlZF9sYWJlbGVkLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlID0gInZpb2xpbiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRyYXdfcXVhbnRpbGVzID0gYygwLjI1LDAuNSwwLjc1KSkKY3Rfbl92YXJfcG9zdGZpbHRlcl9wbG90CgoKZ2dzYXZlKCJnZ3NhdmUvY3Rfbl92YXJfcG9zdGZpbHRlcl9wbG90LnBkZiIsIAogICAgICAgY3Rfbl92YXJfcG9zdGZpbHRlcl9wbG90LCBoZWlnaHQgPSAzLCB3aWR0aCA9IDMpCgpzYXZlUkRTKGN0X25fdmFyX3Bvc3RmaWx0ZXJfcGxvdCwgImN0X25fdmFyX3Bvc3RmaWx0ZXJfcGxvdC5yZHMiKQpgYGAKCmBgYHtyfQojIFF1YW50aWxlIGluZm9ybWF0aW9uIGZvciB0aGUgdmlvbGluIHBsb3QgYWJvdmUKcHJpbnQoc2FtcGxlc19uX3ZhciAlPiUgCiAgZmlsdGVyKElOU1RSVU1FTlRfUkVTVUxUPDI2ICYgbl92YXIgPCAzMCkgJT4lIHB1bGwobl92YXIpICU+JSBxdWFudGlsZSguLHByb2JzID0gYygwLDAuMjUsMC41LDAuNzUpKSkKCnByaW50KHNhbXBsZXNfbl92YXIgJT4lIAogIGZpbHRlcihJTlNUUlVNRU5UX1JFU1VMVDwyNiAmIG5fdmFyIDwgMzApICU+JSBwdWxsKElOU1RSVU1FTlRfUkVTVUxUKSAlPiUgcXVhbnRpbGUoLixwcm9icyA9IGMoMCwwLjI1LDAuNSwwLjc1KSkpCmBgYAoKYGBge3J9CnNhbXBsZXNfbl92YXIgJT4lIHB1bGwobl92YXIpICU+JSBzdW1tYXJ5KCkKYGBgCgojIyBSZXByb2R1Y2liaWxpdHkgb2YgbWlub3IgdmFyaWFudHMKCgpgYGB7cn0KbWlub3JzX3RhYmxlPC0gZnJlYWQoInJlcGxpY2F0ZWRfc2FtcGxlcy5jc3YiLCBkYXRhLnRhYmxlPUYpICU+JSAKICBmaWx0ZXIoTUNvVk51bWJlciAlaW4lIHNhbXBsZXNfbl92YXIkTUNvVk51bWJlcikgJT4lIAogIGZpbHRlcihtYWpvci5vcmlnaW5hbCAlaW4lIGMoIkEiLCJDIiwiVCIsIkciKSkgJT4lIAogIGZpbHRlcihtaW5vci5vcmlnaW5hbCAlaW4lIGMoIkEiLCJDIiwiVCIsIkciKSkgJT4lCiAgZmlsdGVyKHRvdGFsY291bnQub3JpZ2luYWw+PTEwMCAmIG1pbm9yZnJlcS5vcmlnaW5hbD49MC4wMSAmIHRvdGFsY291bnQub3JpZ2luYWwqbWlub3JmcmVxLm9yaWdpbmFsPj01MCAmIAogICAgICAgICAgIHRvbG93ZXIoYmlub2NoZWNrLm9yaWdpbmFsKSE9ImZhbHNlIikgJT4lIGZpbHRlcigoIW50cG9zICVpbiUgcHJpbWVyX3Bvc2l0aW9uc19hbGwpKSAlPiUgCiAgZmlsdGVyKCFudHBvcyAlaW4lIDE6MjY1KSAlPiUgZmlsdGVyKCFudHBvcz4yOTY3NCkKI3dhcyB0aGUgc2FtZSBtaW5vciB2YXJpYW50IGZvdW5kIGluIHRoZSBzZWNvbmQgcmVwbGljYXRlPyBpZiBub3QsIHNldCBtaW5vciBmcmVxdWVuY3kgdG8gMCBpbiBzZWNvbmQgcmVwCm1pbm9yc190YWJsZTwtbWlub3JzX3RhYmxlICU+JSAKICBtdXRhdGUobWlub3JmcmVxLnJlc2VxPWlmX2Vsc2UobWlub3Iub3JpZ2luYWw9PW1pbm9yLnJlc2VxLCBtaW5vcmZyZXEucmVzZXEsIDApKSAlPiUgCiAgbXV0YXRlKGRldGVjdGVkX21pbm9yX2luX3JlcGw9aWZfZWxzZShtaW5vci5vcmlnaW5hbD09bWlub3IucmVzZXEsInllcyIsIm5vIikpCgp3cml0ZV9mZWF0aGVyKG1pbm9yc190YWJsZSwgInByb2Nlc3NpbmcvbWlub3JzX3RhYmxlLmFycm93IikKYGBgCgpgYGB7cn0KI2hvdyB3ZWxsIGFyZSBtaW5vciB2YXJpYW50cyByZWNvdmVyZWQgaW4gc2FtcGxlcyB3aXRoIGRpZmZlcmVudCBDdCB2YWx1ZXM/Cm1pbm9yc190YWJsZSA8LSBtaW5vcnNfdGFibGUgJT4lIGxlZnRfam9pbihzZWxlY3QobWNvdl9zYW1wbGVzLCBNQ29WTnVtYmVyLCBDVD1JTlNUUlVNRU5UX1JFU1VMVCkpICU+JSAKICBtdXRhdGUoc2FtcGxlQ1RfYmluID0gY2FzZV93aGVuKENUPDI2IH4gImJlbG93IDI2IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBDVD49MjYmQ1Q8PTM1IH4iQ1QgMjYtMzUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIENUPjM1JkNUPDUwIH4iZ3JlYXRlciB0aGFuIDM1IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBDVD4xMDB+InVua25vd24iLCAjYXB0aW1hIGluc3RydW1lbnQgdXNlcyBSTFUgbm90IENUCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaXMubmEoQ1QpIH4gInVua25vd24iKSkgCigoCiAgcmVwX2N0PC1taW5vcnNfdGFibGUgJT4lIAogIGdncGxvdChhZXMoeD1taW5vcmZyZXEub3JpZ2luYWwsIHk9bWlub3JmcmVxLnJlc2VxLCBjb2xvcj1kZXRlY3RlZF9taW5vcl9pbl9yZXBsKSkgKyAKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMoInJlZCIsImJsYWNrIikpICsgZ2VvbV9wb2ludChhbHBoYT0wLjUpICsgCiAgZmFjZXRfd3JhcCh+c2FtcGxlQ1RfYmluKSArIHRoZW1lX2J3KCkgKyBsYWJzKHg9Ik1BRiBpbiByZXBsaWNhdGUgMSIsIHk9Ik1BRiBpbiByZXBsaWNhdGUgMiIpICsgCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJib3R0b20iKQopKQoKYGBgCgpgYGB7cn0KI2hvdyB3ZWxsIGFyZSBtaW5vciB2YXJpYW50cyByZWNvdmVyZWQgaW4gc2FtcGxlcyB3aXRoIGRpZmZlcmVudCBtZWRpYW4gY292ZXJhZ2U/CnJlcF9kZXB0aCA8LSBtaW5vcnNfdGFibGUgJT4lIGxlZnRfam9pbihjb3ZlcmFnZV9sZXZlbHMsIGJ5PWMoIk1Db1ZOdW1iZXIiPSJzYW1wbGVuYW1lIikpICU+JSAKICBtdXRhdGUoY292ZXJhZ2VfYmluPWN1dChtZWRpYW5fY292ZXJhZ2UsIDQpKSAlPiUgCiAgZ2dwbG90KGFlcyh4PW1pbm9yZnJlcS5vcmlnaW5hbCwgeT1taW5vcmZyZXEucmVzZXEsIGNvbG9yPWRldGVjdGVkX21pbm9yX2luX3JlcGwpKSArIAogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygicmVkIiwiYmxhY2siKSkgKyBnZW9tX3BvaW50KGFscGhhPTAuNSkgKyAKICBmYWNldF93cmFwKH5jb3ZlcmFnZV9iaW4pICsgdGhlbWVfYncoKSArIAogIGxhYnMoeD0iTUFGIGluIHJlcGxpY2F0ZSAxIiwgeT0iTUFGIGluIHJlcGxpY2F0ZSAyIikgKyAKICB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiLCBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChjb2xvcj1jKDEsMCwxLDApKSkgKyAKICBsYWJzKGNhcHRpb249IlJlcHJvZHVjaWJpbGl0eSBpbiBzYW1wbGVzIHdpdGggZGlmZmVyZW50IG1lZGlhbiBkZXB0aHMiKQojaW4gdGhlIHJhbmdlIG9mIEN0IHZhbHVlcy9jb3ZlcmFnZSBvYnNlcnZlZCBoZXJlLCByZXByb2R1Y2liaWxpdHkgc2VlbXMgbW9yZSBhc3NvY2lhdGVkIHdpdGggQ3QgdGhhbiB3aXRoIGNvdmVyYWdlIApgYGAKCmBgYHtyfQojd2hhdCdzIHRoZSBkaXN0cmlidXRpb24gb2YgZGVwdGgvTUFGIGluIHJlcHJvZHVjaWJsZSB2cy4gbm9uLXJlcHJvZHVjaWJsZSBtaW5vciB2YXJpYW50cz8KcmVwX2RlcHRoX2ZyZXEgPC0gbWlub3JzX3RhYmxlICU+JSBnZ3Bsb3QoYWVzKHg9dG90YWxjb3VudC5vcmlnaW5hbCwgeT1taW5vcmZyZXEub3JpZ2luYWwpKSArIAogIGdlb21fcG9pbnQoYWxwaGE9MC41KSArIGZhY2V0X2dyaWQoZGV0ZWN0ZWRfbWlub3JfaW5fcmVwbH4uKSArIHRoZW1lX2J3KCkgKyAKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChjb2xvcj1jKDEsMCwxLDApKSkgKyB4bGFiKCJTZXEgZGVwdGggaW4gcmVwIDEiKSArIAogIHlsYWIoIk1BRiBpbiByZXAgMSIpICsgbGFicyhjYXB0aW9uPSJSZXByb2R1Y2liaWxpdHkgYXQgc2l0ZXMgd2l0aCBkaWZmZXJlbnQgZGVwdGggYW5kIE1BRiIpCiNkZXB0aCBhbmQgZnJlcXVlbmN5IG9mIG1pbm9yIHZhcmlhbnRzIGlzIGFsc28gbm90IHZlcnkgZGlmZmVyZW50IGJldHdlZW4gcmVwcm9kdWNpYmxlIGFuZCBub24tcmVwcm9kdWNpYmxlIHZhcmlhbnRzCmBgYAoKYGBge3J9CnJlcF9tdXRhdGlvbnMgPC0gbWlub3JzX3RhYmxlICU+JSBmaWx0ZXIoZGV0ZWN0ZWRfbWlub3JfaW5fcmVwbD09InllcyIpIApub25yZXBfbXV0YXRpb25zIDwtIG1pbm9yc190YWJsZSAlPiUgZmlsdGVyKGRldGVjdGVkX21pbm9yX2luX3JlcGw9PSJubyIpIAoKcGxvdF9yZXByb2R1Y2libGVfc3BlY3RyYV9oZWF0bWFwIDwtIHRhYmxlKHJlcF9tdXRhdGlvbnMkbWFqb3Iub3JpZ2luYWwsIHJlcF9tdXRhdGlvbnMkbWlub3Iub3JpZ2luYWwpICU+JSAKICBkYXRhLmZyYW1lKCkgJT4lIGdncGxvdChhZXMoeD1WYXIxLCB5PVZhcjIsIGZpbGw9RnJlcS9zdW0oRnJlcSkpKSArIAogIGdlb21fdGlsZShjb2xvdXIgPSAiYmxhY2siKSArICMgZ3JpZCBjb2xvdXIKICBzY2FsZV9maWxsX2dyYWRpZW50KGxvdyA9ICJ3aGl0ZSIsCiAgICAgICAgICAgICAgICAgICAgICBoaWdoID0gImRhcmtibHVlIikgKwogIHRoZW1lX21pbmltYWwoKSArIGxhYnMoZmlsbCA9ICJGcmFjdGlvbiIsCiAgICAgICB4ID0gIkNvbnNlbnN1cyBhbGxlbGUiLAogICAgICAgeSA9ICJNaW5vciBhbGxlbGUiLCB0aXRsZT0iUmVwcm9kdWNpYmxlIikKCgpwbG90X25vbnJlcHJvZHVjaWJsZV9zcGVjdHJhX2hlYXRtYXAgPC0gdGFibGUobm9ucmVwX211dGF0aW9ucyRtYWpvci5vcmlnaW5hbCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5vbnJlcF9tdXRhdGlvbnMkbWlub3Iub3JpZ2luYWwpICU+JSAKICBkYXRhLmZyYW1lKCkgJT4lIGdncGxvdChhZXMoeD1WYXIxLCB5PVZhcjIsIGZpbGw9RnJlcS9zdW0oRnJlcSkpKSArIAogIGdlb21fdGlsZShjb2xvdXIgPSAiYmxhY2siKSArIAogIHNjYWxlX2ZpbGxfZ3JhZGllbnQobG93ID0gIndoaXRlIiwKICAgICAgICAgICAgICAgICAgICAgIGhpZ2ggPSAiZGFya2JsdWUiKSArCiAgdGhlbWVfbWluaW1hbCgpICsgbGFicyhmaWxsID0gIkZyYWN0aW9uIiwKICAgICAgIHggPSAiQ29uc2Vuc3VzIGFsbGVsZSIsCiAgICAgICB5ID0gIk1pbm9yIGFsbGVsZSIsIHRpdGxlPSJOb24tcmVwcm9kdWNpYmxlIikKCnNhdmVSRFMocGxvdF9ub25yZXByb2R1Y2libGVfc3BlY3RyYV9oZWF0bWFwLCBmaWxlID0gInBsb3Rfbm9ucmVwcm9kdWNpYmxlX3NwZWN0cmFfaGVhdG1hcC5yZHMiKQpzYXZlUkRTKHBsb3RfcmVwcm9kdWNpYmxlX3NwZWN0cmFfaGVhdG1hcCwgZmlsZSA9ICJwbG90X3JlcHJvZHVjaWJsZV9zcGVjdHJhX2hlYXRtYXAucmRzIikKCiMgUGxvdHRlZCBpbiBSTUQgMDMuCmBgYAoKCmBgYHtyfQpyZXBfaW5kaXZfc2FtcGxlcyA8LSBtaW5vcnNfdGFibGUgJT4lIGdncGxvdChhZXMoeD1taW5vcmZyZXEub3JpZ2luYWwsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHk9bWlub3JmcmVxLnJlc2VxLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvcj1kZXRlY3RlZF9taW5vcl9pbl9yZXBsKSkgKyAKICBnZW9tX3BvaW50KGFscGhhPTAuNSkgKyBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMoInJlZCIsImJsYWNrIikpICsgCiAgZmFjZXRfd3JhcChDVH5NQ29WTnVtYmVyKSArIHRoZW1lX2J3KCkgKyB4bGFiKCJNQUYgaW4gcmVwbGljYXRlIDEiKSArIAogIHlsYWIoIk1BRiBpbiByZXBsaWNhdGUgMiIpICsgCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIiwgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoY29sb3I9YygxLDAsMSwwKSkpCmBgYAoKYGBge3IsIGZpZy5oZWlnaHQgPSAxMH0KI1NVUFAgRklHIDEKcmVwbGljYXRlX21lZ2FfcGxvdCA9IHBsb3RfZ3JpZCgKICBwbG90X2dyaWQocmVwX2N0LCAKICAgICAgICAgICAgcGxvdF9ncmlkKHJlcF9kZXB0aCwgcmVwX2RlcHRoX2ZyZXEsIG5jb2w9MiwgcmVsX3dpZHRocz1jKDEuMiwxKSwgCiAgICAgICAgICAgICAgICAgICAgICBsYWJlbHM9YygiYiIsImMiKSksIG5yb3c9MiwgbGFiZWxzPWMoImEiLE5BKSksIAogIHJlcF9pbmRpdl9zYW1wbGVzLCBsYWJlbHM9YyhOQSwgImQiKSwgcmVsX3dpZHRocz1jKDEuMSwxKSkKCmdnc2F2ZSgiZ2dzYXZlL3JlcGxpY2F0ZV9tZWdhX3Bsb3QucGRmIiwgcGxvdCA9IHJlcGxpY2F0ZV9tZWdhX3Bsb3QsIGhlaWdodCA9IDgsIHdpZHRoID0gMTQuNSkKCmBgYAoKCldpbGwgbGltaXQgYW5hbHlzZXMgdG8gc2FtcGxlcyB3aXRoIENUPDI2LCB3aGVyZSB3ZSBhcmUgbW9yZSBjb25maWRlbnQgaW4gcmVwcm9kdWNpYmlsaXR5IG9mIG1pbm9yIHZhcmlhbnQKCgpgYGB7cn0Kc2FtcGxlc19uX3ZhciAlPiUgZmlsdGVyKElOU1RSVU1FTlRfUkVTVUxUPDI2ICYgbl92YXIgPCAzMCkgJT4lIHB1bGwobl92YXIpICU+JSBxdWFudGlsZShjKDAuNSwwLjcpKQpgYGAKCmBgYHtyfQpzYW1wbGVzX3RvX2FuYWx5emUgPC0gc2FtcGxlc19uX3ZhciAlPiUgZmlsdGVyKElOU1RSVU1FTlRfUkVTVUxUPDI2ICYgbl92YXIgPCAzMCkgJT4lIHB1bGwoTUNvVk51bWJlcikKbGluZWFnZXNfZmlndXJlIDwtIG1jb3Zfc2FtcGxlc19maWx0ZXJlZCAlPiUgCiAgZmlsdGVyKE1Db1ZOdW1iZXIgJWluJSBzYW1wbGVzX3RvX2FuYWx5emUpICU+JSAKICBtdXRhdGUodmFyaWFudD1jYXNlX3doZW4oc3RhcnRzV2l0aChzY29ycGlvX2NhbGwsIkRlbHRhIikgfiAiRGVsdGEiLAogICAgICAgIHN0YXJ0c1dpdGgoc2NvcnBpb19jYWxsLCJBbHBoYSIpIH4gIkFscGhhIiwKICAgICAgICAhKHN0YXJ0c1dpdGgoc2NvcnBpb19jYWxsLCJEZWx0YSIpfAogICAgICAgICAgICBzdGFydHNXaXRoKHNjb3JwaW9fY2FsbCwiQWxwaGEiKSkgfiAib3RoZXIiKSkgJT4lCiAgbXV0YXRlKHZhcmlhbnQ9aWZfZWxzZShsaW5lYWdlID09ICJCLjEuMiIsIkIuMS4yIix2YXJpYW50KSkgJT4lCiAgbXV0YXRlKG1vbnRoID0gZmxvb3JfZGF0ZShDT0xMRUNUSU9OX0RULCAibW9udGgiKSkgJT4lCiAgZ2dwbG90KGFlcyh4PW1vbnRoKSkgKyBnZW9tX2JhcihhZXMoZmlsbD12YXJpYW50KSkgICsgCiMgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1jKCIjMDBBMDhBIiwgIiNGMkFEMDAiLCAiI0Y5ODQwMCIsICIjNUJCQ0Q2IikpICsgCiAgeGxhYigiQ29sbGVjdGlvbiBkYXRlIikgKyB5bGFiKCJOby4gc2FtcGxlcyIpICsgICBzY2FsZV94X2RhdGUobGFiZWxzID0gZGF0ZV9mb3JtYXQoIiVtLSVZIikpICsKICBnZ3RpdGxlKHBhc3RlMCgnRmluYWwgc2FtcGxlIHNldCwgXG4gQ3Q8MjYgJiBuX3ZhcjwzMCwgbiA9ICcsbGVuZ3RoKHNhbXBsZXNfdG9fYW5hbHl6ZSkpKSArIAogIHNjYWxlX3hfZGF0ZShtaW5vcl9icmVha3M9IjEgbW9udGgiKSArIHRoZW1lX3B1YnIoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgdmp1c3QgPSAuNSksIGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKQoKI1NVUFAgRklHIDIKbGluZWFnZXNfZmlndXJlCnNhdmVSRFMobGluZWFnZXNfZmlndXJlLCAiZ2dzYXZlL2xpbmVhZ2VzX2ZpZ3VyZS5yZHMiKQpnZ3NhdmUoImdnc2F2ZS9saW5lYWdlc19maWd1cmUucGRmIiwgcGxvdCA9IGxpbmVhZ2VzX2ZpZ3VyZSwgaGVpZ2h0ID0gNCwgd2lkdGggPSA1KQpgYGAKCmBgYHtyfQpzYW1wbGVzX25fdmFyICU+JSBmaWx0ZXIoSU5TVFJVTUVOVF9SRVNVTFQ8MjYpICU+JSBwdWxsKG5fdmFyKSAlPiUgc3VtbWFyeSgpCmBgYAoKYGBge3J9CiNwbG90X2dyaWQoY292ZXJhZ2VfcHJlX2ZpbHRlcmluZywgY3RfaW5jbHVzaW9uLCBuY29sPTIsIGxhYmVscz1jKCJhIiwiYiIpKQpgYGAKCmBgYHtyfQptaW5vcl9zaXRlc19sb3djdDwtbWlub3JfdmFyaWFudF9zaXRlc190aHJlc2hvbGQgJT4lIGxlZnRfam9pbihtY292X3NhbXBsZXNfZmlsdGVyZWQpICU+JSAKICBmaWx0ZXIoSU5TVFJVTUVOVF9SRVNVTFQ8MjYpIApgYGAKCgojIFdoYXQga2luZHMgb2YgcnVuLXNwZWNpZmljIGVmZmVjdHMgZG8gd2Ugc2VlIGV2ZW4gYWZ0ZXIgZmlsdGVyaW5nIGZvciBoaWdoLXF1YWxpdHkgc2FtcGxlcz8KCmBgYHtyfQojYXJlIHJ1biBlZmZlY3RzIHJlbGF0ZWQgdG8gc2VxdWVuY2luZyBkZXB0aD8Kbl92YXJfYnlfY292ZXJhZ2U8LXNhbXBsZXNfbl92YXIgJT4lIGZpbHRlcihJTlNUUlVNRU5UX1JFU1VMVDwyNiAmIG5fdmFyIDwgMzApICU+JSBnZ3Bsb3QoYWVzKHg9bWVkaWFuX2NvdmVyYWdlLCB5PW5fdmFyKSkgKyBnZW9tX3BvaW50KGFscGhhPTAuMDUpICsgCiAgZ2VvbV9kZW5zaXR5XzJkKGNvbG9yID0gInNhbG1vbiIpICsgZ2VvbV9zbW9vdGgoY29sb3IgPSAicmVkIikgKyB0aGVtZV9wdWJyKCkgKwogIHNjYWxlX3hfY29udGludW91cyhsaW1pdHMgPSBjKDAsIDE1MDAwKSkgKwogIHhsYWIoIlNhbXBsZSBtZWRpYW4gY292ZXJhZ2UiKSArIHlsYWIoIm5fdmFyIikgKyBzdGF0X2NvcihtZXRob2QgPSAic3BlYXJtYW4iLCBjb3IuY29lZi5uYW1lID0gInJobyIpCm5fdmFyX2J5X2NvdmVyYWdlCiNub3Qgb24gdGhlIGluZGl2aWR1YWwgc2FtcGxlIGxldmVsCgojaXMgYXZlcmFnZSBtaW5vciB2YXJpYW50IHJpY2huZXNzIGluIGEgcnVuIHJlbGF0ZWQgdG8gYXZlcmFnZSBkZXB0aCBvZiBjb3ZlcmFnZSBpbiB0aGUgcnVuPwpuX3Zhcl9kZXB0aF9hdmVyYWdlczwtc2FtcGxlc19uX3ZhciAlPiUgZmlsdGVyKElOU1RSVU1FTlRfUkVTVUxUPDI2ICYgbl92YXIgPCAzMCkgJT4lIAogIGdyb3VwX2J5KHJ1bikgJT4lIAogIHN1bW1hcmlzZShtZWRpYW5fbl92YXI9bWVkaWFuKG5fdmFyKSwgCiAgICAgICAgICAgIG1lZGlhbl9zYW1wbGVfY292ZXJhZ2U9bWVkaWFuKG1lZGlhbl9jb3ZlcmFnZSksIAogICAgICAgICAgICBtZWRpYW5fY3Q9bWVkaWFuKElOU1RSVU1FTlRfUkVTVUxUKSkgJT4lIAogIGdncGxvdChhZXMoeD1tZWRpYW5fc2FtcGxlX2NvdmVyYWdlLCB5PW1lZGlhbl9uX3ZhcikpICsgZ2VvbV9wb2ludChhbHBoYSA9IDAuNSkgKwogIHNjYWxlX3hfY29udGludW91cyhsaW1pdHMgPSBjKDAsIDE1MDAwKSkgKwogIHRoZW1lX3B1YnIoKSArIHhsYWIoIlJ1biBtZWRpYW4gb2YgbWVkaWFuIGNvdmVyYWdlIikgKyB5bGFiKCJSdW4gbWVkaWFuIG5fdmFyIikgKyAKICBnZW9tX3Ntb290aChjb2xvciA9ICJyZWQiKSArIHN0YXRfY29yKG1ldGhvZCA9ICJzcGVhcm1hbiIsIGNvci5jb2VmLm5hbWUgPSAicmhvIikKbl92YXJfZGVwdGhfYXZlcmFnZXMKYGBgCgpgYGB7ciwgZmlnLmhlaWdodCA9IDUsIGZpZy53aWR0aCA9IDR9Cm5fdmFyX2J5X3J1biA8LSBzYW1wbGVzX25fdmFyICU+JSBtdXRhdGUocnVuID0gYXMubnVtZXJpYyhzdHJfcmVtb3ZlKHJ1biwgIlJ1bl8iKSkpICU+JSAKICBmaWx0ZXIoSU5TVFJVTUVOVF9SRVNVTFQgPCAyNiAmIG5fdmFyIDwgMzApICU+JSAKICAgIGdncGxvdChhZXMoeD1ydW4sIHk9bl92YXIsIGdyb3VwID0gcnVuKSkgKyBnZW9tX2JveHBsb3QoKSArIAogICAgc2NhbGVfZmlsbF9ncmV5KHN0YXJ0ID0gMSwgZW5kID0gMC44KSArIAogICAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgxMCw5MCwyKSwgbGltaXRzID0gYygxMCw5MiksIGxhYmVscyA9IGxhYmVsX2F0KDEwKSkgKwogICAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLDMwLDIpLCBsYWJlbHMgPSBsYWJlbF9hdCgxMCkpICsKCiAgICBzY2FsZV9jb2xvcl9ncmV5KHN0YXJ0PTAsIGVuZD0wLjYpICsgCiAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IC41KSkKCnBsb3RzX2J5X3J1biA9IGdnYXJyYW5nZShmMywgZjQsIG5fdmFyX2J5X3J1biwgbGFiZWxzID0gbGlzdCgiQSIsIkIiLCJEIiksIAogICAgICAgICAgbmNvbCA9IDEsIG5yb3cgPSAzLCBhbGlnbiA9ICJ2IiwgY29tbW9uLmxlZ2VuZCA9IFQpICU+JSBhbm5vdGF0ZV9maWd1cmUoLiwKICAgICAgICAgICAgICAgdG9wID0gdGV4dF9ncm9iKCJyZWQgY2lyY2xlczogc2FtcGxlcyBDdD40MCIsIGNvbG9yID0gInJlZCIsIHNpemUgPSAxMCkpCgpkb3RzX2RlcHRoX21lZGlhbiA9IGdnYXJyYW5nZShuX3Zhcl9ieV9jb3ZlcmFnZSwgbl92YXJfZGVwdGhfYXZlcmFnZXMsICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gbGlzdCgiRSIsICJGIiksIG5jb2wgPSAxKQoKZG90c19wbG90cyA9IGdnYXJyYW5nZShydW5zX3NhbXBsZXNfZG90cywgZG90c19kZXB0aF9tZWRpYW4sIGxhYmVscyA9IGxpc3QoIkMiKSwgCiAgICAgICAgICAgICAgICAgICAgICAgbmNvbCA9IDEsIGhlaWdodHMgPSBjKDEsMSkpCgpydW5fZmlsdHJhdGlvbiA9IGdnYXJyYW5nZShwbG90c19ieV9ydW4sIGRvdHNfcGxvdHMsIG5jb2wgPSAyLCB3aWR0aHMgPSBjKDIuNSwgMSkpCnJ1bl9maWx0cmF0aW9uCmdnc2F2ZSgiZ2dzYXZlL3J1bl9maWx0cmF0aW9uLnBkZiIsIHJ1bl9maWx0cmF0aW9uLCBoZWlnaHQgPSA4LCB3aWR0aCA9IDEyKQpgYGAK